Adding an args argument to OpenLayers.String.format. This lets you set context properties as functions that will be executed with the given arguments where tokens match. For styles, this means you can specify a context that contains functions that return some value based on the feature being styled. See the styles-context.html example for use. r=ahocevar (closes #1434)

git-svn-id: http://svn.openlayers.org/trunk/openlayers@6512 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
Tim Schaub
2008-03-12 22:24:33 +00:00
parent 7a25a14f93
commit 106e73618a
4 changed files with 263 additions and 11 deletions

View File

@@ -0,0 +1,216 @@
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers Vector Styles</title>
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
<style type="text/css">
#map {
width: 800px;
height: 400px;
border: 1px solid black;
}
</style>
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
var map;
function init(){
map = new OpenLayers.Map('map', {maxResolution:'auto'});
var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
map.addLayer(wms);
map.setCenter(new OpenLayers.LonLat(0, 0), 0);
// Strategy 1: Style features based on some attribute.
// create 50 random features in the northern hemisphere
// give them a "type" attribute that will be used to style
// them by size
var features = new Array(50);
for (var i=0; i<features.length; i++) {
features[i] = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(
(360 * Math.random()) - 180, 90 * Math.random()
), {
type: 5 + parseInt(5 * Math.random())
}
);
}
// create the layer styleMap with a simple symbolizer template
var layer1 = new OpenLayers.Layer.Vector('Points', {
styleMap: new OpenLayers.StyleMap({
pointRadius: "${type}", // based on feature.attributes.type
fillColor: "#666666"
})
});
layer1.addFeatures(features);
// Strategy 2: Style features based on something besides attributes.
// create 50 random features in the southern hemisphere
var features = new Array(50);
for (var i=0; i<features.length; i++) {
features[i] = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(
(360 * Math.random()) - 180, -90 * Math.random()
), {
type: 5 + parseInt(5 * Math.random())
}
);
}
// create the layer styleMap by giving the default style a context
var colors = ["red", "green", "blue"];
var context = {
getColor: function(feature) {
var region = parseInt((feature.geometry.x + 180) / 120);
return colors[region];
},
getType: function(feature) {
return feature.attributes["type"];
}
};
var template = {
pointRadius: "${getType}", // using context.getType(feature)
fillColor: "${getColor}" // using context.getColor(feature)
};
var style = new OpenLayers.Style(template, {context: context});
var layer2 = new OpenLayers.Layer.Vector('Points', {
styleMap: new OpenLayers.StyleMap(style)
});
layer2.addFeatures(features);
map.addLayers([layer1, layer2]);
}
</script>
</head>
<body onload="init()">
<h1 id="title">Feature Styles Example</h1>
<div id="tags"></div>
<p id="shortdesc">
Shows how to create a feature styles.
</p>
<div id="map"></div>
<div id="docs">
<p>Features in the northern hemisphere are styled according to their
"type" attribute. This is accomplished with a simple template that
is evaluated with the feature attributes as context.</p>
<p>Features in the sourthern hemisphere are styled according to a
combination of their attributes and non-attribute properties. This
is accomplished using an advanced template that calls functions
on the context object passed to the Style constructor.</p>
</div>
</body>
</html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenLayers Vector Styles</title>
<link rel="stylesheet" href="../theme/default/style.css" type="text/css" />
<style type="text/css">
#map {
width: 800px;
height: 400px;
border: 1px solid black;
}
</style>
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
var map;
function init(){
map = new OpenLayers.Map('map', {maxResolution:'auto'});
var wms = new OpenLayers.Layer.WMS( "OpenLayers WMS",
"http://labs.metacarta.com/wms/vmap0", {layers: 'basic'} );
map.addLayer(wms);
map.setCenter(new OpenLayers.LonLat(0, 0), 0);
// Strategy 1: Style features based on some attribute.
// create 50 random features in the northern hemisphere
// give them a "type" attribute that will be used to style
// them by size
var features = new Array(50);
for (var i=0; i<features.length; i++) {
features[i] = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(
(360 * Math.random()) - 180, 90 * Math.random()
), {
type: 5 + parseInt(5 * Math.random())
}
);
}
// create the layer styleMap with a simple symbolizer template
var layer1 = new OpenLayers.Layer.Vector('Points', {
styleMap: new OpenLayers.StyleMap({
pointRadius: "${type}", // based on feature.attributes.type
fillColor: "#666666"
})
});
layer1.addFeatures(features);
// Strategy 2: Style features based on something besides attributes.
// create 50 random features in the southern hemisphere
var features = new Array(50);
for (var i=0; i<features.length; i++) {
features[i] = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(
(360 * Math.random()) - 180, -90 * Math.random()
), {
type: 5 + parseInt(5 * Math.random())
}
);
}
// create the layer styleMap by giving the default style a context
var colors = ["red", "green", "blue"];
var context = {
getColor: function(feature) {
var region = parseInt((feature.geometry.x + 180) / 120);
return colors[region];
},
getType: function(feature) {
return feature.attributes["type"];
}
};
var template = {
pointRadius: "${getType}", // using context.getType(feature)
fillColor: "${getColor}" // using context.getColor(feature)
};
var style = new OpenLayers.Style(template, {context: context});
var layer2 = new OpenLayers.Layer.Vector('Points', {
styleMap: new OpenLayers.StyleMap(style)
});
layer2.addFeatures(features);
map.addLayers([layer1, layer2]);
}
</script>
</head>
<body onload="init()">
<h1 id="title">Feature Styles Example</h1>
<div id="tags"></div>
<p id="shortdesc">
Shows how to create a feature styles.
</p>
<div id="map"></div>
<div id="docs">
<p>Features in the northern hemisphere are styled according to their
"type" attribute. This is accomplished with a simple template that
is evaluated with the feature attributes as context.</p>
<p>Features in the sourthern hemisphere are styled according to a
combination of their attributes and non-attribute properties. This
is accomplished using an advanced template that calls functions
on the context object passed to the Style constructor.</p>
</div>
</body>
</html>

View File

@@ -106,22 +106,31 @@ OpenLayers.String = {
* context - {Object} An optional object with properties corresponding
* to the tokens in the format string. If no context is sent, the
* window object will be used.
* args - {Array} Optional arguments to pass to any functions found in
* the context. If a context property is a function, the token
* will be replaced by the return from the function called with
* these arguments.
*
* Returns:
* {String} A string with tokens replaced from the context object.
*/
format: function(template, context) {
format: function(template, context, args) {
if(!context) {
context = window;
}
var tokens = template.split("${");
var item, last;
var item, last, replacement;
for(var i=1; i<tokens.length; i++) {
item = tokens[i];
last = item.indexOf("}");
if(last > 0) {
tokens[i] = context[item.substring(0, last)] +
item.substring(++last);
if(last > 0) {
replacement = context[item.substring(0, last)];
if(typeof replacement == "function") {
replacement = args ?
replacement.apply(null, args) :
replacement();
}
tokens[i] = replacement + item.substring(++last);
} else {
tokens[i] = "${" + item;
}

View File

@@ -196,7 +196,7 @@ OpenLayers.Style = OpenLayers.Class({
var context = this.context || feature.attributes || feature.data;
for (var i in this.propertyStyles) {
style[i] = OpenLayers.Style.createLiteral(style[i], context);
style[i] = OpenLayers.Style.createLiteral(style[i], context, feature);
}
return style;
},
@@ -315,20 +315,22 @@ OpenLayers.Style = OpenLayers.Class({
* into a Literal, taking the property values from the passed features.
*
* Parameters:
* value {String} value to parse. If this string contains a construct like
* value - {String} value to parse. If this string contains a construct like
* "foo ${bar}", then "foo " will be taken as literal, and "${bar}"
* will be replaced by the value of the "bar" attribute of the passed
* feature.
* context {Object} context to take attribute values from
* context - {Object} context to take attribute values from
* feature - {OpenLayers.Feature.Vector} The feature that will be passed
* to <OpenLayers.String.format> for evaluating functions in the context.
*
* Returns:
* {String} the parsed value. In the example of the value parameter above, the
* result would be "foo valueOfBar", assuming that the passed feature has an
* attribute named "bar" with the value "valueOfBar".
*/
OpenLayers.Style.createLiteral = function(value, context) {
OpenLayers.Style.createLiteral = function(value, context, feature) {
if (typeof value == "string" && value.indexOf("${") != -1) {
value = OpenLayers.String.format(value, context)
value = OpenLayers.String.format(value, context, [feature]);
value = isNaN(value) ? value : parseFloat(value);
}
return value;

View File

@@ -89,7 +89,7 @@
"", "${ ", "${", " ${", "${${", "${}", "${${}}", " ${ ${",
"}", "${${} }"
]
t.plan(4 + unchanged.length);
t.plan(6 + unchanged.length);
var format = OpenLayers.String.format;
@@ -114,6 +114,31 @@
var context = {bar: "foo", foo: "bar"};
t.eq(format("a ${bar} is a ${foo}", context), "a foo is a bar",
"multiple properties replaced correctly");
// test context with properties that are functions
var context = {
bar: "church",
getDrunk: function() {
return arguments[0];
}
};
t.eq(
format("I go to the ${bar} to ${getDrunk}.", context, ["eat pretzels"]),
"I go to the church to eat pretzels.",
"function correctly called in context with arguments"
);
// test that things don't break
var context = {
meaning: function(truth) {
return truth;
}
};
t.eq(
format("In life, truth is ${meaning}.", context),
"In life, truth is undefined.",
"still works if arguments are not supplied"
);
}