|
POST
|
Why not create an array of features (graphics) and use setFeatures as normal? The Graphic class allows you to transform data in any format to an object the api understands. I use php and mysql to store records which are primarily created and edited through web forms, and viewed in reports outside the mapping application. But they have a geographic component, mostly point geometry (x/y). I use both user based queries and pseudo-feature layers (a graphics layer wired up for onPanEnd and onZoomEnd to request using map bounds). The records aren't returned in the same format as arcgis server returns them. So I create graphics with the results, and use them just like I would with ags results from query, identify, etc. As far as handling multiple features per record: var features = [];
dojo.forEach(results), function (result) {
dojo.forEach(result.features, function (feat) {
var graphic = new esri.Graphic();
graphic.setSymbol(SOME_SYMBOL);
graphic.setGeometry(feat.geometry);
graphic.setAttribures({
resultId: result.id,
featureId: feat.id,
field1: result.field1,
field2: result.field2
});
graphic.setInfoTemplate(new esri.infoTemplate('My Features', '${*}');
features.push(graphic);
});
});
... View more
10-04-2013
11:37 AM
|
0
|
0
|
1298
|
|
POST
|
//CONTINUED FROM LAST POST
_setContent: function (message) {
if (lang.isFunction(message)) {
message(this);
return;
}
//MODIFY if the toaster is visible simply switch out the current message with new message
/*if(message && this.isVisible){
message = this.contentNode.innerHTML + this.separator + message;
}*/
this.contentNode.innerHTML = message;
},
_cancelHideTimer: function () {
if (this._hideTimer) {
clearTimeout(this._hideTimer);
this._hideTimer = null;
}
},
_setHideTimer: function (duration) {
this._cancelHideTimer();
//if duration == 0 we keep the message displayed until clicked
if (duration > 0) {
this._cancelHideTimer();
this._hideTimer = setTimeout(lang.hitch(this, function (evt) {
// we must hide the iframe in order to fade
// TODO: figure out how to fade with a BackgroundIframe
if (this.bgIframe && this.bgIframe.iframe) {
this.bgIframe.iframe.style.display = "none";
}
this._hideTimer = null;
//force clear sticky message
this._stickyMessage = false;
this.fadeAnim.play();
}), duration);
} else
this._stickyMessage = true;
},
_placeClip: function () {
//MODIFY view is the map (or other container) and border is its border
//var view = window.getBox();
var pos = domGeometry.position(this.mapId);
var view = {
w: pos.w,
h: pos.h,
t: pos.y,
l: pos.x
};
var border = domGeometry.getBorderExtents(this.mapId);
var nodeSize = domGeometry.getMarginBox(this.containerNode);
var style = this.clipNode.style;
// sets up the size of the clipping node
style.height = nodeSize.h + "px";
style.width = nodeSize.w + "px";
// sets up the position of the clipping node
var pd = this.positionDirection;
if (pd.match(/^t/)) {
//MODIFY + border top
//style.top = view.t+"px";
style.top = (view.t + border.t) + "px";
} else if (pd.match(/^b/)) {
//MODIFY + border top
//style.top = (view.h - nodeSize.h - 2 + view.t)+"px";
style.top = (view.h - nodeSize.h - 2 + view.t + border.t) + "px";
}
if (pd.match(/^[tb]r-/)) {
style.left = (view.w - nodeSize.w - 1 - view.l) + "px";
} else if (pd.match(/^[tb]l-/)) {
//MODIFY [top/bottom]-left set to view left + left border width
//style.left = 0 + "px";
style.left = (view.l + border.l) + "px";
} else if (pd.match(/^[tb]c-/)) {
//MODIFY [top/bottom]-center is view/2 + view left + border left - node/2
//style.left = Math.round((view.w - nodeSize.w - 1 - view.l)/2)+"px";
style.left = (Math.round(view.w / 2) + view.l + border.l - (nodeSize.w / 2)) + "px";
}
style.clip = "rect(0px, " + nodeSize.w + "px, " + nodeSize.h + "px, 0px)";
if (has("ie")) {
if (!this.bgIframe) {
//MODIFY registry.getUniqueId
//this.clipNode.id = registry.getUniqueId("dojox_widget_Toaster_clipNode");
this.clipNode.id = registry.getUniqueId("mods_widget_MapToaster_clipNode");
this.bgIframe = new BackgroundIframe(this.clipNode);
}
var iframe = this.bgIframe.iframe;
if (iframe) {
iframe.style.display = "block";
}
}
},
onSelect: function ( /*Event*/ e) {
// summary:
// callback for when user clicks the message
},
show: function () {
// summary:'
// show the Toaster
domStyle.set(this.domNode, 'display', 'block');
this._placeClip();
if (!this._scrollConnected) {
this._scrollConnected = connect.connect(window, "onscroll", this, this._placeClip);
}
},
hide: function () {
// summary:
// hide the Toaster
domStyle.set(this.domNode, 'display', 'none');
if (this._scrollConnected) {
connect.disconnect(this._scrollConnected);
this._scrollConnected = false;
}
domStyle.set(this.containerNode, "opacity", 1);
}
});
}); The css: /* map toaster */
.dijitMapToasterContent {
padding:0.75em;
background:#B5BCC7;
/*background-color:rgb(181,188,199);
background-color:rgba(181,188,199,0.9);*/
text-align:center;
-webkit-border-radius:0px 0px 10px 10px;
border-radius:0px 0px 10px 10px;
}
.dijitMapToasterMessage{
/*color:#fff;*/
}
.dijitMapToasterWarning,
.dijitMapToasterError,
.dijitMapToasterFatal{
font-weight:bold;
color:#fff;
}
.dijitMapToasterWarning .dijitMapToasterContent{
background:#900;
}
.dijitMapToasterError .dijitMapToasterContent{
background:#990;
}
.dijitMapToasterClip {
position: absolute;
z-index: 5000;
overflow: hidden;
}
.dijitMapToasterContainer {
display: block;
position: absolute;
width: 200px;
margin: 0px;
/*font:0.75em;*/
} Create it with the added parameter mapId for the id of the map div, not the map object itself. app.map.toaster = new mods.widget.MapToaster({ mapId: 'center-map', defaultType: 'message', duration: 3500, positionDirection: 'tc-down' }); Call for it: app.map.toaster.setContent('Click map to draw point.'); Not generally this forthcoming with stuff like this, but guess what: I clicked on the link in your post and saw myself asking a question that never got answered. Forgot about that. Mine didn't get answered but yours will.
... View more
10-03-2013
02:40 PM
|
0
|
0
|
1145
|
|
POST
|
I GUESS THERE'S A CHARACTER LIMIT SO THIS IS COMING IN TWO PARTS... It's the default nature of the toaster is to have the window as it's container. It's a modification to the widget time! Here's my modification to 1) set the target to the map (or any other element with an id) and 2) add center down. I started to add center up but never did. The the other positions may or may not work. As I recall there was an issue with right. All I wanted was center down so I didn't go any further or clean it up (probably buried 42 pages deep in my to do list). Notes: The namespace and class are changed to mods.widget.MapToaster. Change to your custom module path. Of course all dojo module naming and path conventions must be followed. Anything I changed is proceeded with //MODIFY and a brief description of the change. This is uncompressed and still contains the author's comments. The widget code: define([ "dojo/_base/declare", // declare "dojo/_base/lang", // lang.getObject... "dojo/_base/connect", // connect.connect, connect.subscribe "dojo/_base/fx", // fx.fadeOut "dojo/dom-style", // domStyle.set "dojo/dom-class", // domClass.add "dojo/dom-geometry", // domGeometry.getMarginBox "dijit/registry", // registry.getUniqueId() "dijit/_WidgetBase", "dijit/_TemplatedMixin", "dijit/BackgroundIframe", "dojo/fx", "dojo/has", "dojo/_base/window", "dojo/window" ], function (declare, lang, connect, baseFx, domStyle, domClass, domGeometry, registry, WidgetBase, Templated, BackgroundIframe, coreFx, has, baseWindow, window) { lang.getObject("dojox.widget", true); var capitalize = function ( /* String */ w) { return w.substring(0, 1).toUpperCase() + w.substring(1); }; //MODIFY dojox.widget.Toaster to mods.widget.MapToaster return declare("mods.widget.MapToaster", [WidgetBase, Templated], { // summary: // Message that slides in from the corner of the screen, used for notifications // like "new email". //MODIFY add "Map" to classes templateString: '<div class="dijitMapToasterClip" dojoAttachPoint="clipNode"><div class="dijitMapToasterContainer" dojoAttachPoint="containerNode" dojoAttachEvent="onclick:onSelect"><div class="dijitMapToasterContent" dojoAttachPoint="contentNode"></div></div></div>', // messageTopic: String // Name of topic; anything published to this topic will be displayed as a message. // Message format is either String or an object like // {message: "hello word", type: "error", duration: 500} messageTopic: "", // messageTypes: Enumeration // Possible message types. messageTypes: { MESSAGE: "message", WARNING: "warning", ERROR: "error", FATAL: "fatal" }, // defaultType: String // If message type isn't specified (see "messageTopic" parameter), // then display message as this type. // Possible values in messageTypes enumeration ("message", "warning", "error", "fatal") defaultType: "message", // positionDirection: String // Position from which message slides into screen, one of // ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right"] //MODIFY default to "tc-down" positionDirection: "tc-down", // positionDirectionTypes: Array // Possible values for positionDirection parameter //MODIFY add direction types "bc-up" and "tc-down" positionDirectionTypes: ["br-up", "br-left", "bl-up", "bl-right", "tr-down", "tr-left", "tl-down", "tl-right", "bc-up", "tc-down"], // duration: Integer // Number of milliseconds to show message duration: 2000, // slideDuration: Integer // Number of milliseconds for the slide animation, increasing will cause the Toaster // to slide in more slowly. slideDuration: 500, // separator: String // String used to separate messages if consecutive calls are made to setContent before previous messages go away //MODIFY no need for separator - see _setContent //separator: "<hr></hr>", //MODIFY map div (or other container) id mapId: 'map', postCreate: function () { this.inherited(arguments); this.hide(); // place node as a child of body for positioning baseWindow.body().appendChild(this.domNode); if (this.messageTopic) { connect.subscribe(this.messageTopic, this, "_handleMessage"); } }, _handleMessage: function ( /*String|Object*/ message) { if (lang.isString(message)) { this.setContent(message); } else { this.setContent(message.message, message.type, message.duration); } }, setContent: function ( /*String|Function*/ message, /*String*/ messageType, /*int?*/ duration) { // summary: // sets and displays the given message and show duration // message: // the message. If this is a function, it will be called with this toaster widget as the only argument. // messageType: // type of message; possible values in messageTypes enumeration ("message", "warning", "error", "fatal") // duration: // duration in milliseconds to display message before removing it. Widget has default value. duration = duration || this.duration; // sync animations so there are no ghosted fades and such if (this.slideAnim) { if (this.slideAnim.status() != "playing") { this.slideAnim.stop(); } if (this.slideAnim.status() == "playing" || (this.fadeAnim && this.fadeAnim.status() == "playing")) { setTimeout(lang.hitch(this, function () { this.setContent(message, messageType, duration); }), 50); return; } } // determine type of content and apply appropriately for (var type in this.messageTypes) { //MODIFY add "Map" to classes domClass.remove(this.containerNode, "dijitMapToaster" + capitalize(this.messageTypes[type])); } domStyle.set(this.containerNode, "opacity", 1); this._setContent(message); //MODIFY add "Map" to classes domClass.add(this.containerNode, "dijitMapToaster" + capitalize(messageType || this.defaultType)); // now do funky animation of widget appearing from // bottom right of page and up this.show(); var nodeSize = domGeometry.getMarginBox(this.containerNode); this._cancelHideTimer(); if (this.isVisible) { this._placeClip(); //update hide timer if no sticky message in stack if (!this._stickyMessage) { this._setHideTimer(duration); } } else { var style = this.containerNode.style; var pd = this.positionDirection; // sets up initial position of container node and slide-out direction if (pd.indexOf("-up") >= 0) { style.left = 0 + "px"; style.top = nodeSize.h + 10 + "px"; } else if (pd.indexOf("-left") >= 0) { style.left = nodeSize.w + 10 + "px"; style.top = 0 + "px"; } else if (pd.indexOf("-right") >= 0) { style.left = 0 - nodeSize.w - 10 + "px"; style.top = 0 + "px"; } else if (pd.indexOf("-down") >= 0) { style.left = 0 + "px"; style.top = 0 - nodeSize.h - 10 + "px"; } else { throw new Error(this.id + ".positionDirection is invalid: " + pd); } this.slideAnim = coreFx.slideTo({ node: this.containerNode, top: 0, left: 0, duration: this.slideDuration }); this.connect(this.slideAnim, "onEnd", function (nodes, anim) { //we build the fadeAnim here so we dont have to duplicate it later // can't do a fadeHide because we're fading the // inner node rather than the clipping node this.fadeAnim = baseFx.fadeOut({ node: this.containerNode, duration: 1000 }); this.connect(this.fadeAnim, "onEnd", function (evt) { this.isVisible = false; this.hide(); }); this._setHideTimer(duration); this.connect(this, 'onSelect', function (evt) { this._cancelHideTimer(); //force clear sticky message this._stickyMessage = false; this.fadeAnim.play(); }); this.isVisible = true; }); this.slideAnim.play(); } }, //CONTINUED IN NEXT POST
... View more
10-03-2013
02:39 PM
|
0
|
0
|
1145
|
|
POST
|
Cheers! Back when I first started using floating panes I had the same issues with the resizer and resizing. The solution at the time was static dimensions. Grids and custom mods with complex layout and lots of resizing were particularly difficult to work with in a floating pane. I never went back and just created closeable tabs for a tab container for those sorts of things. At any rate, you've inspired me to revisit floating panes while going to AMD. I can think of several items I'd like to get into a floating pane. Cheers and good luck to you!
... View more
10-03-2013
09:44 AM
|
0
|
2
|
3400
|
|
POST
|
I've never used resizing or have scrolling. I size the floating pane to fit the content without overflow. I was able to get a quick solution based on my example code above to be placed below the focus and show events. dojo.connect(mapinfofp, 'resize', function() { dojo.style(mapinfofp.canvas, 'height', dojo.style(mapinfofp.canvas, 'height') - 18 + 'px') } ); 18px seems to be enough. The problem I see with this is always having the extra "padding" on the bottom even when no scroll bars are showing. I suppose you could check to see if the cavas node is scrolling before changing the height. This is obviously non-AMD.
... View more
10-03-2013
07:00 AM
|
0
|
0
|
3400
|
|
POST
|
Check this out. http://resources.arcgis.com/en/help/main/10.1/index.html#/Printing_maps_that_contain_secured_services/0154000005q3000000/ There is a procedure for adding server user names and passwords when creating a print service before publishing.
... View more
10-02-2013
02:03 PM
|
0
|
0
|
947
|
|
POST
|
WKID is an number and not a string. Whatever the zona_utm variable is, it's a string. You can see this in the request parameters. Bad request {"wkid":"32717"} Good request {"wkid":32717} parseInt() to get an number. var wkid = parseInt(zona_utm); var point = new esri.geometry.Point([este,norte],new esri.SpatialReference({ wkid: wkid }));
... View more
10-01-2013
01:43 PM
|
0
|
0
|
637
|
|
POST
|
JS API Team, Calling graphicsExtent with a single point returns null. I get why this happens, i.e. a single point doesn't have an extent (height and width = 0). When iterating through graphics and zooming to one graphic I can understand filtering in code. For example: zoomTo: function (gId) {
array.forEach(this.map.resultsLayer.graphics, function (graphic) {
if (graphic.gId === gId) {
if (graphic.geometry.type === 'point') {
this.map.centerAndZoom(graphic.geometry, 18);
} else {
this.map.setExtent(graphic.geometry.getExtent(), true);
}
return;
}
});
} I don't mind checking for a single point myself and handling it, but it seems to me graphicsExtent should catch a single point in the graphics array and return a valid extent. Perhaps with a second parameter that when set to true returns a computed extent for a single point. I'm not sure what that would look like from the api's point of view, but something that comes to mind is returning an extent based on map size at the largest level of detail with the point as the center. Just a suggestion and as always keep up the good work.
... View more
09-30-2013
12:15 PM
|
0
|
8
|
8163
|
|
POST
|
They look like dojo buttons. If they are, you can get html style tooltips by setting the title parameter. new Button({
label: 'My Button',
title: 'Click this button to do something cool',
iconClass: 'iconCool',
onClick: function () {
}
}) [HTML] <div data-dojo-type="dijit/form/Button" data-dojo-props="label: 'My Button', title: 'Click this button to do something cool', iconClass: 'iconCool', onClick: function () { }"></div>[/HTML]
... View more
09-25-2013
10:23 AM
|
0
|
0
|
1291
|
|
POST
|
Jon is right. If you are just learning the api AMD is the way to go. I wasn't sold on it at first, but it's quickly growing on me. Don't box yourself in by spending time writing a legacy app that will require migration in the near future to keep up with the api.
... View more
09-25-2013
10:16 AM
|
0
|
0
|
1006
|
|
POST
|
Jose, You can download the SDK's http://www.esri.com/apps/products/download/index.cfm?fuseaction=download.all#ArcGIS_API_for_JavaScript here. Not sure what version switched to AMD. For sure 3.2 was still legacy.
... View more
09-25-2013
06:16 AM
|
0
|
0
|
1006
|
|
POST
|
Howdy. Have you looked here http://resources.arcgis.com/en/help/main/10.2/index.html#/What_is_a_geoprocessing_service/00570000005w000000/ Lots of info below this entry on creating and publishing gp services. Not sure what you mean by "not lining up". Having issues creating and publishing a gp service? Do you have a gp service published but can't interact with it through your js application? Or is it something else? Just a tip: Most folks on the forum won't engage threads which don't contain detailed info on the problem, code samples, etc. Good luck.
... View more
09-24-2013
11:12 AM
|
0
|
0
|
549
|
|
POST
|
I think you have too many equal signs. 3 === is the match type and value operator. You're trying to set the drawing tool to a value. Try: selectedTemplate.template.drawingTool = 'esriFeatureEditToolFreehand';
... View more
09-24-2013
06:33 AM
|
0
|
0
|
1285
|
|
POST
|
You can still set lods when creating a map. Not sure why it's no longer listed in the reference. //the map
app.map = new esri.Map('center-map', {
lods: config.map.lods,
basemap: config.map.basemap,
center: config.map.center,
zoom: config.map.zoom,
logo: config.map.logo,
showAttribution: config.map.showAttribution
}); As always if you use Web Mercator basemaps you must use standard lods.
... View more
09-17-2013
08:48 AM
|
0
|
0
|
589
|
|
POST
|
Hey Derek, I read Brian Timoney's article last time you linked it when someone asked this same question a while back. I agree with anti-portal sentiments myself as a web user looking for specific information. However, I'd like to make the argument the jsapi should have a TOC widget. Not everyone is developing applications for the web. Like ACM, I'm not creating applications for the public. I'm developing full featured portals with lots of layers, tools and tasks designed for the intranet. My users have the app open all day and use it for several aspects of the company's operations. Since editing, some more advanced features of the api, html5, etc have come along, I can't keep up with requests for new layers and functionalities. The TOC is where layer functionality is initiated. Case in point, the ArcGIS Online Map. Layer transparency, layer order, setting scales, etc. In my case identify, query, geoprocessing, editing and more are all initiated through the TOC for services, sub-layers and feature layers. The jsapi is, in my opinion, the most complete and versatile web mapping api ESRI offers. Combined with everything dojo does it lends itself to creating complex applications. Google Maps is great for creating a feature specific map someone comes across while using a search engine to search for dog parks (not that the jsapi isn't), but GMaps isn't the api to build a full-featured web based GIS primarily using ArcGIS Server and all it's capabilities. Just today I saw Matt Driscoll's post on the upcoming swipe widget, which only goes to show that the jsapi is the api for high functioning web based GIS. I just feel a TOC is just too critical a component not to be included with the api in some form at this point in its evolution. As always, keep up the good work. Ben
... View more
09-16-2013
05:50 PM
|
0
|
0
|
352
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 06-18-2013 06:56 AM | |
| 1 | 06-30-2015 09:17 AM | |
| 1 | 10-12-2013 07:14 AM | |
| 1 | 02-05-2014 11:05 AM | |
| 1 | 05-28-2015 11:41 AM |
| Online Status |
Offline
|
| Date Last Visited |
11-11-2020
02:23 AM
|