Add support for the extremely awesomely super-comprehensive rule based styling

that Andreas has been working so hard on. I think this is the single most
awesome commit I've ever had the pleasure of committing. The results of this
commit are described on http://trac.openlayers.org/wiki/Styles: essentially,
this makes it possible to style features in all kinds of fun ways based on
rules, and will also form the underlying basis for #533. Things this patch
adds:

 * OL.Rule classes. These classes allow you to do tests against the propertie
   of a feature, and set a style based on these properties -- so you can
   compare the 'speedlimit' property of a line, and test if it is > 60, and if
   it is greater than 60, render it in a different color. You can also test
   combinations of rules using the OL.Rule.Logical class, and test featureids
   with the FeatureID class. 
 * OL.Style class: The OL.Style class lets you wrap up Rules into styles that 
   can be used with drawFeature to draw the feature in the selected style.
 * OL.Layer.Vector.drawFeature will check if the given style is an OL.Style
   object, and if so, it will draw the feature accordingly.

examples/georss-flickr.html shows usage of these classes.

Many, many thanks go to Andreas for all his hard work on this: this code really
is very pretty, and includes unit tests for all the classes (and we know that I
am a big fan of tests.)

Three cheers for Andreas: Hip hip, hooray! hip hip, hooray! hip hip, hooray!


git-svn-id: http://svn.openlayers.org/trunk/openlayers@5429 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
crschmidt
2007-12-15 16:17:50 +00:00
parent 43a4f9320b
commit fb3c02354f
15 changed files with 1851 additions and 0 deletions
+70
View File
@@ -0,0 +1,70 @@
<html>
<head>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_Comparison_constructor(t) {
t.plan(3);
var options = {'foo': 'bar'};
var rule = new OpenLayers.Rule.Comparison(options);
t.ok(rule instanceof OpenLayers.Rule.Comparison,
"new OpenLayers.Rule.Comparison returns object" );
t.eq(rule.foo, "bar", "constructor sets options correctly");
t.eq(typeof rule.evaluate, "function", "rule has an evaluate function");
}
function test_Comparison_destroy(t) {
t.plan(1);
var rule = new OpenLayers.Rule.Comparison();
rule.destroy();
t.eq(rule.symbolizer, null, "symbolizer hash nulled properly");
}
function test_Comparison_value2regex(t) {
t.plan(2);
var rule = new OpenLayers.Rule.Comparison({
property: "foo",
value: "*b?r\\*\\?*",
type: OpenLayers.Rule.Comparison.LIKE});
rule.value2regex("*", "?", "\\");
t.eq(rule.value, ".*b.r\\*\\?.*", "Regular expression generated correctly.");
rule.value = "%b.r!%!.%";
rule.value2regex("%", ".", "!");
t.eq(rule.value, ".*b.r\\%\\..*", "Regular expression with different wildcard and escape chars generated correctly.");
}
function test_Comparison_evaluate(t) {
t.plan(3);
var rule = new OpenLayers.Rule.Comparison({
property: "area",
lowerBoundary: 1000,
upperBoundary: 5000,
type: OpenLayers.Rule.Comparison.BETWEEN});
var features = [
new OpenLayers.Feature.Vector(null, {
area: 2000}),
new OpenLayers.Feature.Vector(null, {
area: 6000}),
new OpenLayers.Feature.Vector(null, {
area: 4999})];
var ruleResults = {
0: true,
1: false,
2: true};
for (var i in ruleResults) {
var result = rule.evaluate(features[i]);
t.eq(result, ruleResults[i], "feature "+i+
" evaluates to "+result.toString()+" correctly.");
}
}
</script>
</head>
<body>
</body>
</html>
+47
View File
@@ -0,0 +1,47 @@
<html>
<head>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_FeatureId_constructor(t) {
t.plan(3);
var options = {'foo': 'bar'};
var rule = new OpenLayers.Rule.FeatureId(options);
t.ok(rule instanceof OpenLayers.Rule.FeatureId,
"new OpenLayers.Rule.FeatureId returns object" );
t.eq(rule.foo, "bar", "constructor sets options correctly");
t.eq(typeof rule.evaluate, "function", "rule has an evaluate function");
}
function test_FeatureId_destroy(t) {
t.plan(1);
var rule = new OpenLayers.Rule.FeatureId();
rule.destroy();
t.eq(rule.symbolizer, null, "symbolizer hash nulled properly");
}
function test_FeatureId_evaluate(t) {
t.plan(3);
var rule = new OpenLayers.Rule.FeatureId(
{fids: ["fid_1", "fid_3"]});
var ruleResults = {
"fid_1" : true,
"fid_2" : false,
"fid_3" : true};
for (var i in ruleResults) {
var feature = new OpenLayers.Feature.Vector();
feature.fid = i;
var result = rule.evaluate(feature);
t.eq(result, ruleResults[i], "feature "+i+" evaluates to "+result.toString()+" correctly.");
feature.destroy();
}
}
</script>
</head>
<body>
</body>
</html>
+41
View File
@@ -0,0 +1,41 @@
<html>
<head>
<script src="../../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_Logical_constructor(t) {
t.plan(3);
var options = {'foo': 'bar'};
var rule = new OpenLayers.Rule.Logical(options);
t.ok(rule instanceof OpenLayers.Rule.Logical,
"new OpenLayers.Rule.Logical returns object" );
t.eq(rule.foo, "bar", "constructor sets options correctly");
t.eq(typeof rule.evaluate, "function", "rule has an evaluate function");
}
function test_Logical_destroy(t) {
t.plan(1);
var rule = new OpenLayers.Rule.Logical();
rule.destroy();
t.eq(rule.children, null, "children array nulled properly");
}
function test_Logical_evaluate(t) {
t.plan(1);
var rule = new OpenLayers.Rule.Logical({
type: OpenLayers.Rule.Logical.NOT});
rule.children.push(new OpenLayers.Rule());
var feature = new OpenLayers.Feature.Vector();
t.eq(rule.evaluate(feature), false,
"feature evaluates to false correctly.");
}
</script>
</head>
<body>
</body>
</html>
+5
View File
@@ -35,6 +35,11 @@
<li>Popup/test_AnchoredBubble.html</li>
<li>test_Feature.html</li>
<li>Feature/test_Vector.html</li>
<li>test_Style.html</li>
<li>test_Rule.html</li>
<li>Rule/test_FeatureId.html</li>
<li>Rule/test_Logical.html</li>
<li>Rule/test_Comparison.html</li>
<li>test_Events.html</li>
<li>test_Util.html</li>
<li>test_Layer.html</li>
+29
View File
@@ -0,0 +1,29 @@
<html>
<head>
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_Rule_constructor(t) {
t.plan(3);
var options = {'foo': 'bar'};
var rule = new OpenLayers.Rule(options);
t.ok(rule instanceof OpenLayers.Rule,
"new OpenLayers.Rule returns object" );
t.eq(rule.foo, "bar", "constructor sets options correctly");
t.eq(typeof rule.evaluate, "function", "rule has an evaluate function");
}
function test_Rule_destroy(t) {
t.plan(1);
var rule = new OpenLayers.Rule();
rule.destroy();
t.eq(rule.symbolizer, null, "symbolizer hash nulled properly");
}
</script>
</head>
<body>
</body>
</html>
+79
View File
@@ -0,0 +1,79 @@
<html>
<head>
<script src="../lib/OpenLayers.js"></script>
<script type="text/javascript">
function test_Style_constructor(t) {
t.plan(3);
var options = {'foo': 'bar'};
var style = new OpenLayers.Style(null, options);
t.ok(style instanceof OpenLayers.Style,
"new OpenLayers.Style returns object" );
t.eq(style.foo, "bar", "constructor sets options correctly");
t.eq(typeof style.createStyle, "function", "style has a createStyle function");
}
function test_Style_create(t) {
t.plan(5);
var map = new OpenLayers.Map("map");
var layer = new OpenLayers.Layer.Vector("layer");
var baseStyle = {externalGraphic: "bar${foo}.png"};
var style = new OpenLayers.Style(baseStyle);
var rule = new OpenLayers.Rule.FeatureId({
fids: ["1"],
symbolizer: {"Point": {fillColor: "green"}},
maxScale: 2000000});
style.addRules([rule]);
var feature = new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(3,5),
{"foo": "bar"},
style);
feature.fid = "1";
// for this fid, the above rule should apply
layer.addFeatures([feature]);
map.addLayer(layer);
map.setBaseLayer(layer);
map.setCenter(new OpenLayers.LonLat(3,5), 8);
// at this scale, the feature should be visible
var createdStyle = style.createStyle(feature);
t.eq(createdStyle.externalGraphic, "barbar.png", "Calculated property style correctly.");
t.eq(createdStyle.display, "", "Feature is visible at scale "+map.getScale());
map.setCenter(new OpenLayers.LonLat(3,5), 7);
// at this scale, the feature should be invisible
createdStyle = style.createStyle(feature);
t.eq(createdStyle.display, "none", "Feature is invisible at scale "+map.getScale());
t.eq(createdStyle.fillColor, "green", "Point symbolizer from rule for fid=\"1\" applied correctly.");
feature.fid = "2";
// now the rule should not apply
createdStyle = style.createStyle(feature);
t.eq(createdStyle.fillColor, undefined, "Correct style for rule that does not apply to fid=\"2\".");
}
function test_Style_destroy(t) {
t.plan(1);
var style = new OpenLayers.Style();
style.destroy();
t.eq(style.rules, null, "rules array nulled properly");
}
</script>
</head>
<body>
<div id="map" style="width:500px;height:500px"></div>
</body>
</html>