|
POST
|
Found it! When specifying the color in my symbology, I was using just the hex value. I should have been defining a color based on the hex value instead. color = new Color(col); sym = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, polyOutlineSymbol, color);
... View more
08-07-2014
08:13 AM
|
0
|
0
|
1302
|
|
POST
|
I am using something I found at gitHub that will help me classify my data, change classes, colors etc. It was a little rough, but I got it working and my layer is drawing. The problem is in the way the color is formatted. I'm pulling it out an predetermined array and the function is converting it to hex. Somewhere in here I've defined my color such that the legend doesn't like it and it's failing when I create it. The color is defined as hex returned from the function in the format #ffee000. I using these to create a simplefillsymbol for a classbreakrenderer breakData is what is getting returned from my function. It is in the format {"breaks": [{"interval":0.9 , "color":"#fee5d9" },{"interval":5.95 , "color":"#fcae91" },{"interval":11.26 , "color":"#fb6a4a" },{"interval":19.77 , "color":"#de2d26" },{"interval":27.86 , "color":"#a50f15" }]} I've also returned the array of break points so I can use it for my max/min of the classbreaks. breaks = [0.9, 3.99, 8.92, 11.98, 16.97, 23.8, 30.02, 64.08]; Note: I couldn't figure how how to specify just a min value and symbol, without a maxValue in between when specifying a new break. I thought I could put a 'null' in addBreak, but I couldn't figure out how to skip over it. ------------------------------------------------------------------- var br = new ClassBreaksRenderer(defaultSymbol, findBreakValue); //using a function here instead of a field var breakData = JSON.parse(jstyle); var int,nextup, nextInt, col,color, sym; for (var j in breakData.breaks){ int = breakData.breaks .interval; nextup = parseInt(j) + 1; nextInt = classBr[nextup]; if (!nextInt) { nextInt = highestValue; } col = breakData.breaks .color; color = new Color(col); sym = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID, polyOutlineSymbol, col); //polyOutlineSymbol defined earlier as a thin gray line br.addBreak(int, nextInt, sym); } featureLayer.setRenderer(br); featureLayer.redraw(); var legend = new Legend({ map: map, layerInfos: [{ "layer": featureLayer, "title": "Value" }] },"legend"); legend.startup(); I get an error: TypeError: b.color.toRgba is not a function during the legend creation. The map displays correctly, with the classification and colors as defined. I assume the legend doesn't like the way I formatted the color for my symbology? There seems to be lots of variations on defining your color, hex, rgb, rgba.
... View more
08-07-2014
08:01 AM
|
0
|
1
|
1732
|
|
POST
|
Now that I look at this more closely, only the graphics within the featureLayer have the new attributes. That isn't something that percolates back to featureLayer.fields. Since generateRendererParameters is looking for a field, it is failing. Is there a workaround to this? It seems like a lot of work to create a FeatureCollection instead just so I have the fields for the task. Maybe I should just go back to the original gas price mash up and generate the breaks manually.
... View more
08-04-2014
09:02 AM
|
0
|
0
|
1190
|
|
POST
|
I need to combine my JSON file to an existing featureLayer, adding additional attributes that I want to use to render my polygons. I'm using the example https://developers.arcgis.com/javascript/jssamples/data_gas_prices.html I have stepped through my graphics and at the end of that looping, my featureLayer has the new attributes I need. That example is calculating the class breaks manually, but I'd like to use the generateRendererTask instead. I know I am getting lost in the order of the events. Once I have the new attributes I want to use one of them as the classification field for the renderer. In the functions that I define it, it doesn't yet recognize that attribute as being available. Putting my breakpoints in right after I've looped through the graphics, I believe that it's there. I'm not calling the render functions correctly, or I need to have an event listener set up for the featureLayer. In the original example, there is an update-end listener on the featureLayer. I"m not sure what that's for. I have moved my call to generateClassBreaks to different positions, but I continue to get the error that it can't find my classification field "CROP", which is one of the attributes I introduced from the JSON file.
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no">
<title></title>
<link rel="stylesheet" href="http://js.arcgis.com/3.10/js/esri/css/esri.css">
<link rel="stylesheet" href="css/style.css">
<script type="text/javascript" >var dojoConfig = {
parseOnLoad: false,
async:true,
packages: [{
name: "extras",
location: location.pathname.replace(/\/[^/]+$/, "") + "/extras"
}]
};
</script>
<script type="text/javascript" src="http://js.arcgis.com/3.10/"></script>
<script type="text/javascript" >
var pathName = "https://myserverURL";
var defaultFrom = "#feedde";
var defaultTo = "#e75303";
var interval = 5; //used to generate renderer
require([
"dojo/parser", "dojo/json", "dojo/_base/array", "dojo/_base/connect", "esri/Color",
"dojo/number", "dojo/dom-construct",
"esri/map", "esri/geometry/Extent","esri/SpatialReference", "esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol", "esri/renderers/SimpleRenderer", "esri/renderers/ClassBreaksRenderer",
"esri/layers/FeatureLayer", "esri/dijit/Legend", "esri/request", "extras/Tip",
"esri/tasks/ClassBreaksDefinition", "esri/tasks/AlgorithmicColorRamp",
"esri/tasks/GenerateRendererParameters", "esri/tasks/GenerateRendererTask",
"esri/layers/LayerDrawingOptions",
"dijit/layout/BorderContainer", "dijit/layout/ContentPane", "dojo/domReady!"
], function(
parser, JSON, arrayUtils, conn, Color, number, domConstruct,
Map, Extent, SpatialReference, SimpleLineSymbol, SimpleFillSymbol, SimpleRenderer, ClassBreaksRenderer,
FeatureLayer, Legend, esriRequest, Tip,
ClassBreaksDefinition, AlgorithmicColorRamp,GenerateRendererParameters, GenerateRendererTask, LayerDrawingOptions) {
parser.parse();
spatialReference = new SpatialReference({wkid: 102100 });
var startExtent = new Extent(-10583000, 4287025, -9979000, 4980462, spatialReference);
map = new Map("map", {
extent: startExtent
});
var defaultSymbol = new SimpleFillSymbol(SimpleFillSymbol.STYLE_SOLID,
new SimpleLineSymbol(SimpleLineSymbol.STYLE_SOLID, new Color([182, 182, 182]), 1), new Color([190, 190, 190, 0.7]))
var template = "<strong>${COUNTYNAME}";
tip = new Tip({
"format": template,
"node": "legend"
});
featureLayer = new FeatureLayer(pathName+"/arcgis/rest/services/BaseMap/county_simple/MapServer/0", {
maxAllowableOffset: map.extent.getWidth() / map.width,
mode: FeatureLayer.MODE_SNAPSHOT,
outFields: ["COUNTYNAME"],
visible: true
});
featureLayer.setRenderer(new SimpleRenderer(null));//starts empty
var updateEnd = featureLayer.on("update-end", function() {
updateEnd.remove();
var def = esriRequest({
// url: "http://apify.heroku.com/api/aaagasprices.json",
url: "../json/agChemical2.json",
callbackParamName: "callback"
});
def.then(drawFeatureLayer, drawFeatureError);
generateClassBreaks(defaultFrom, defaultTo);
// wire up the tip
featureLayer.on("mouse-over", tip.showInfo);
featureLayer.on("mouse-out", tip.hideInfo);
});
map.addLayer(featureLayer);
function drawFeatureLayer(data) {
var values = (typeof data === "string" ) ? JSON.parse(data) : data;
arrayUtils.forEach(featureLayer.graphics, function(graphic) {
var rec = values[graphic.attributes.COUNTYNAME];
if (rec) {
var recData = rec[0];
var atts = [];
for(var att in recData){
atts.push(att);
var field = att;
// console.log ('att = ' + att + ", value = " + recData[att]);
graphic.attributes[att] = recData[att];
}
}
});
domConstruct.destroy("loading");
}
//functions for generating symbology for the layer selected
function generateClassBreaks(c1, c2) {
var classDef = new ClassBreaksDefinition();
classDef.classificationField = "CROP";
classDef.classificationMethod = "quantile";
classDef.breakCount = interval; //defined as 5
var colorRamp = new AlgorithmicColorRamp();
colorRamp.fromColor = new Color.fromHex(c1);
colorRamp.toColor = new Color.fromHex(c2);
colorRamp.algorithm = "hsv"; // options are: "cie-lab", "hsv", "lab-lch"
classDef.baseSymbol = defaultSymbol;
classDef.colorRamp = colorRamp;
var params = new GenerateRendererParameters();
params.classificationDefinition = classDef;
// params.precision = 2;
// params.formatLabel = true;
// var clauseInput = classDef.classificationField;
// params.where= clauseInput + " > 0";
var generateRenderer = new GenerateRendererTask(featureLayer);
generateRenderer.on("error", taskErrorHandler);
generateRenderer.execute(params, applyRenderer);
}
function applyRenderer(renderer) {
var optionsArray = [];
renderer.defaultSymbol = defaultSymbol;
var drawingOptions = new LayerDrawingOptions();
drawingOptions.renderer = renderer;
optionsArray[0] = drawingOptions;
agLayer.setLayerDrawingOptions(optionsArray);
featureLayer.redraw();
// getInfoFromRender(renderer);//creates arrays the legend will use
// createLegend();
}
function taskErrorHandler(err){
console.log("error in task is " + err.error);
}
// function used by the class breaks renderer to get the
// value used to symbolize each state
function findBreakValue(graphic) {
ntyValues[COUNTY];
}
function calcBreaks(min, max, numberOfClasses) {
var range = (max - min) / numberOfClasses;
var breakValues = [];
for ( var i = 0; i < numberOfClasses; i++ ) {
breakValues = formatNumber(min + ( range * i ));
}
// console.log("break values: ", breakValues);
return breakValues;
}
function formatNumber(num) {
return number.format(num, { "places": 2 });
}
function drawFeatureError(e) {
console.log("error getting data: ", e);
}
}
);
</script>
</head>
<body>
<div id="loading" class="shadow loading">
Getting Data...
<img src="http://dl.dropbox.com/u/2654618/loading_gray_circle.gif" alt="loading image">
</div>
<div id="legend" class="shadow info"></div>
<div data-dojo-type="dijit.layout.BorderContainer"
data-dojo-props="design:'headline',gutters:false"
style="width: 100%; height: 100%; margin: 0;">
<div id="map"
data-dojo-type="dijit.layout.ContentPane"
data-dojo-props="region:'center'">
<div id="title" class="shadow info">Current Values by County</div>
</div>
</div>
</body>
</html>
... View more
08-04-2014
08:22 AM
|
0
|
2
|
3146
|
|
POST
|
I agree with Stephen. Since the API reference doesn't list 'click' as an event, that's your answer right there, you can't do it that way. I have always used to map click event to either execute a queryTask or identifyTask together with some sort of looping.
... View more
07-30-2014
09:50 AM
|
2
|
0
|
1218
|
|
POST
|
I don't know if this would be a solution for you, but when I have problems with anything that generates output results, like featureLayer.selectFeatures, it helps me to separate it out to an event listener and an resultsHandler. You could try adding a selection-complete handler on your featureLayer and move your function to a separate resultsHandler that would execute only when your selection is complete. Sometimes the problem is the results handler is running before the execute is really fully finished. The frustrating thing too is that if you add breakpoints it sometimes works! It can be because the pause of a breakpoint was just enough time for the query to finish.
... View more
07-29-2014
01:13 PM
|
0
|
0
|
1865
|
|
POST
|
Glad you figured it out. I was having some very weird behavior with my copy/paste, so I was manually trying to type out the parts that weren't right. I fixed my answer so other people will have the right syntax.
... View more
07-29-2014
01:05 PM
|
0
|
1
|
2206
|
|
POST
|
I have mine placed on the map events. This works pretty well since then I don't have to track which type of layer is currently loading. I have a loading image within my mapDiv <img id="loadingImg" src="images/loading.gif" alt="Loading image" style="position:absolute; left:350px; top:250px; z-index:100;" /> var loading = dom.byId("loadingImg"); map.on('update-start', showLoading); map.on('update-end', hideLoading); function showLoading(){ domUtils.show(loading); map.disableMapNavigation(); map.hideZoomSlider(); } function hideLoading(error){ domUtils.hide(loading); map.enableMapNavigation(); map.showZoomSlider(); }
... View more
07-29-2014
12:02 PM
|
0
|
4
|
2206
|
|
POST
|
I was specifically trying to get to 2, so leaving the precision parameters out wasn't a solution. The only way I've been able to manipulate the legend the way I wanted was to create it from scratch, making my own rectangles, text etc. I am putting the formatted label string into an array, labelArray, and then pulling them out in the createLegend function. You ought to be able to build a formatLabel function that takes itm.minValue and itm.maxValue as input to format it the way you want before it goes into labelArray. I pretty much had to do this anyway because I wanted a value for "No Data' and the ability to add some extra legend notes. Continuing with the functions I have earlier, here's the results handler for the generateClassBreaks function. I go on to generate the legend manually.
function applyRenderer(renderer) {
var optionsArray = [];
renderer.defaultSymbol = defaultSymbol;
var drawingOptions = new LayerDrawingOptions();
drawingOptions.renderer = renderer;
optionsArray[0] = drawingOptions;
agLayer.setLayerDrawingOptions(optionsArray);
getInfoFromRender(renderer);//creates arrays the legend will use
createLegend();
}
function getInfoFromRender(renderer){
symbolArray.length = 0;
labelArray.length = 0;
arrayUtils.forEach (renderer.infos, function (itm) {
symbolArray.push(itm.symbol);
var val = itm.minValue + " - " + itm.maxValue;
// labelArray.push(itm.label);
labelArray.push(val);
});
}
// create legend based on symbology defined in code
function createLegend() {
// var divLegend = dom.byId("legendDiv");
domConstruct.empty("legendDiv");
var note = dom.byId('mapHeader').innerHTML;
//change the size of the surface as needed, example: if labels are wider or there are more than 5 intervals
var legendSurface = gfx.createSurface(dom.byId("legendDiv"), 250, 200);
var group = legendSurface.createGroup();
yPos = 20;
var descriptors, legendText;
//symbolArray created as part of the generateRendererTask
arrayUtils.forEach(symbolArray, function (itm, idx){
descriptors = jsonUtils.getShapeDescriptors(itm);
group.createRect({x: 10, y: yPos, width: 30, height: 20 }).
setFill(descriptors.fill).
setStroke(descriptors.stroke);
//labelArray created as part of teh generateRendererTask
legendText = group.createText({ x:45, y:yPos + 15, text:labelArray[idx], align:"start"}).
setFont({ family:"Arial", size:"10pt", weight:"normal" }).
setFill("#000000");
yPos = yPos + 25;
});
// when data value = -999, symbolize as Data Not Available
group.createRect({x: 10, y: yPos, width: 30, height: 20 }).
setFill(jsonUtils.getShapeDescriptors(defaultSymbol).fill).
setStroke(jsonUtils.getShapeDescriptors(defaultSymbol).stroke);
legendText = group.createText({ x:45, y:yPos + 15, text:"Data Not Available", align:"start"}).
setFont({ family:"Arial", size:"10pt", weight:"normal" }).
setFill("#0000");
yPos = yPos + 25;
dom.byId("legendTitle").innerHTML = note +"<br/><i>Percent Total Area Treated</i> " ;
registry.byId('legendPane').set("open", true);
}
... View more
07-29-2014
11:30 AM
|
2
|
1
|
2430
|
|
POST
|
I don't see that you have the outSpatialReference set on your ClosestFacilityParameters. You'd want to specify it the same as your map spatialReference.
... View more
07-25-2014
09:55 AM
|
0
|
0
|
1477
|
|
POST
|
There's not much discussion I can find about this, but I assume since featureLayer is renderer more on the client, it's not included when you use printTask for an ExportWebMapTask? It also sounds like I'm not going to be able to print the infoWindow tag if there is one either. Has anyone come up with a solution they're happy with? I have something, but I'm not very satisfied with it. I have created a graphicsLayer, thinking I could add some graphics and a textSymbol containing what's in the inforWindow. I'm also adding my featureLayer as an ArcGISDynamicMapServiceLayer just long enough to have something to print. I captured the clicked point on the map.infoWindow.show event so I have a place to add a text symbol.
function submitMapPrint() {
var printTitle = registry.byId("txtTitle").get("value");
if (printTitle.length < 1) {
printTitle = "Sample FeatureLayer Print";
}
var printParams = new PrintParameters();
printParams.map = map;
dom.byId("printStatus").innerHTML ="Generating ..." ;
// status.innerHTML = "Generating ...";
var e = registry.byId("templateSelect");
var choice = e.value;
printTemplate = templates[0];
switch (e.value){
case "Portrait":
printTemplate = templates[1];
break;
case "Landscape":
printTemplate = templates[0];
break;
default:
printTemplate = templates[0];
}
printParams.template = printTemplate;
printTemplate.layoutOptions.titleText = printTitle;
showLoading();
createPrintGraphics();
on(map, 'layers-add-result', function (){
showLoading();
pointLayer.clearSelection();
var printTask = new PrintTask(printServiceUrl);
printTask.on('complete', printTaskHandler);
printTask.execute(printParams);
printTask.on('error', function (err){
console.log("error in printTask: " + err.error);
dom.byId("printStatus").innerHTML ="Error generating printout, try again." ;
});
});
}
function printTaskHandler(results) {
var d = new Date();
var dateTime = d.getTime();
var outputUrl = results.result.url + '?time=' + dateTime;
dom.byId("printStatus").innerHTML = "";
var select = registry.byId("templateSelect");
var selectOptions = select.getOptions();
select.set("value", "Choose Print Format");
removePrintGraphics();
hideLoading();
window.open(outputUrl,"_blank");
}
function createPrintGraphics(){
popup.clearFeatures();
map.infoWindow.hide();
var len = pointLayer.url.length -2;
var pointUrl = pointLayer.url.substr(0, len);
printLayer = new ArcGISDynamicMapServiceLayer(pointUrl, {
id: "printLayer"
});
var font = new Font(
"11pt",
Font.STYLE_NORMAL,
Font.VARIANT_NORMAL,
"Helvetica"
);
var text = br2nl(printTag);
var textSymbol = new TextSymbol(
text,
font,
new Color("#00000")
);
var pt = clickPt.offset(1000, 10000);
printTextLayer.add(new Graphic(pt, textSymbol));
var printGraphic = new Graphic(clickPt, symbol);
printTextLayer.add(printGraphic);
map.addLayers([printLayer]);
}
function removePrintGraphics() {
printTextLayer.clear();
map.removeLayer(printLayer);
}
function br2nl(str) {
var newStr = str.replace(/<br\s*\/?>/mg,"\n");
// return str.replace(/<br\s*\/?>/mg,"\n");
newStr = newStr.replace(/<\s*\/?br>/mg, "\n")
newStr = newStr.replace(/<b\s*\/?>/mg,"");
newStr = newStr.replace(/<\s*\/?b>/mg, "")
return newStr;
}
//functions for managing the status icon
function showLoading() {
domUtils.show(loading);
map.disableMapNavigation();
map.hideZoomSlider();
}
function hideLoading(error) {
domUtils.hide(loading);
map.enableMapNavigation();
map.showZoomSlider();
}
This gives me a piece of text on my map, which looks pretty klunky compared to a formatted infoWindow. Of course I'm now missing my nice pin markersymbols too, since the map service has a plain red circle originally. Am I missing something obvious? Is there a better way to do this?
... View more
07-25-2014
09:26 AM
|
0
|
0
|
656
|
|
POST
|
I have some older code I'm trying to get moved to a new server without having to complete rewrite this in AMD. I have a routeTask that take either a geoLocation or a geocoded point and uses them as stops in my RouteParameters. When I execute my RouteTask, there are no errors and I can see results, but the directions returns all paths with Infinity, Infinity, rather than the coordinates I expected to see. My input is set to wkid = 102100 and the I have the spatialReference set to that as well. I had this code working just fine using a 10.0 route service. My new server is 10.2.2. I wouldn't have thought there was a huge difference between the output of the RouteTask, but maybe there is. I'm having problems navigating the API Reference. I'm hoping it means there are more upgrades coming and not that something is just falling apart at ESRI today!
... View more
07-08-2014
01:09 PM
|
0
|
0
|
2049
|
|
POST
|
There is not room to put my whole code and it's not in production so I can't share it with you. I have no idea how to navigate well in this new forum, I could barely get logged in, it took multiple tries to get this far, Some things like yearList and rateList are the results of a queryTask, populated earlier in the code. At least you have an idea of some syntax for the axes. var lineChart = new Chart2D("chartDiv", { title: chartTitle, titlePos:"bottom", titleGap: 12, titleFont: "normal normal normal 13pt Arial" }); lineChart.addPlot("default", { type: "Lines", markers: true, hAxis: "x", vAxis: "y"}); lineChart.addAxis("x", { title:"Rates by Year", titleOrientation:"away", labels: yearList, font: "normal normal normal 9pt Arial", majorLabels: true, minorTicks: false, minorLabels: false, microTicks: false }); lineChart.addAxis("y", { title:rateNote, vertical: true, fixLower: "major", fixUpper: "major", min: 0, max: axisMax, minorTicks: false, minorLabels: true}); lineChart.addSeries("Series 1", rateList, { stroke: { color: "red", width: 2 } } ); var tip = Tooltip(lineChart, "default", { text : function(o) { var yr = yearList[o.x].text; var yrList = parseInt(yr) - 1; return ( yrList +'<br>' + o.y ); } }); lineChart.render();
... View more
07-08-2014
01:00 PM
|
0
|
1
|
1738
|
|
POST
|
The answer to this was as clear as mud, I just happened to try this and it worked. When you specify your classDefinition, there's a place there to set your defaultSymbol. I had one defined based on the example https://developers.arcgis.com/javascript/jssamples/renderer_dynamic_layer_change_attribute.html When you execute the generateRendererTask, the resultant renderer doesn't have a default symbol assigned to it anymore. I don't know if this in intentional or something that is broken in the task. Before I applied this symbology to my layer, I manually went in and set the default symbol again on the renderer. function applyRenderer(renderer) { var optionsArray = []; renderer.defaultSymbol = defaultSymbol; var drawingOptions = new LayerDrawingOptions(); drawingOptions.renderer = renderer; optionsArray[0] = drawingOptions; myLayer.setLayerDrawingOptions(optionsArray); } Now my excluded values of -999 are symbolized with that default and not just blank.
... View more
07-03-2014
11:25 AM
|
0
|
0
|
765
|
|
POST
|
In Desktop, when symbolizing by a numeric value, not only can you specify classification method, interval, field etc, there's also a place to exclude some records. I routinely have data with a value of -999 to indicate 'no data'. In desktop, I can exclude those records from the classification calculation and still have a symbol on them that I can show on the map and legend. I don't see that I can do the same thing with the objects available for classbreaksdefinition and generateRendererTask. If I exclude my 'no data', using a where clause, my classification calculates just fine, but they are completely eliminated from the display. That isn't what I want to see. I can't have those -999 in the calculations, that just gives weird breaks, but I still show them with some 'no data' symbol, not have them completely gone. Am I missing something? It seems like I should be able to do this. I could probably make a second set of function just to display these no data records, but that sounds rather messy.
... View more
07-03-2014
10:44 AM
|
0
|
1
|
2477
|
| Title | Kudos | Posted |
|---|---|---|
| 1 | 06-02-2017 02:38 PM | |
| 2 | 03-18-2022 10:14 AM | |
| 2 | 02-18-2016 06:28 AM | |
| 1 | 03-18-2024 07:29 AM | |
| 4 | 08-02-2023 06:08 AM |
| Online Status |
Offline
|
| Date Last Visited |
02-25-2025
01:56 PM
|