3 <script src="../../lib/OpenLayers.js"></script>
4 <script type="text/javascript">
6 var name = "Vector Layer";
8 function test_Layer_Vector_constructor(t) {
11 var options = {protocol: new OpenLayers.Protocol(),
12 strategies: [new OpenLayers.Strategy(), new OpenLayers.Strategy()]}
13 var layer = new OpenLayers.Layer.Vector(name, options);
15 t.ok(layer instanceof OpenLayers.Layer.Vector, "new OpenLayers.Layer.Vector returns correct object" );
16 t.eq(layer.name, name, "layer name is correctly set");
17 t.ok(layer.renderer.CLASS_NAME, "layer has a renderer");
19 t.ok((layer.name == layer.strategies[0].layer.name) &&
20 (layer.strategies[0].layer.name == layer.strategies[1].layer.name),
21 "setLayer was called on strategies");
24 function test_Layer_Vector_refresh(t) {
27 var obj = {"an": "object"};
30 var layer = new OpenLayers.Layer.Vector(name, {
32 refresh: function(o) {
38 layer.calculateInRange = function() {
44 layer.visibility = false;
46 t.eq(log.obj, undefined, "[false, false] refresh not triggered");
50 layer.visibility = false;
52 t.eq(log.obj, undefined, "[true, false] refresh not triggered");
56 layer.visibility = true;
58 t.eq(log.obj, undefined, "[false, true] refresh not triggered");
62 layer.visibility = true;
64 t.ok(log.obj === obj, "[true, true] refresh triggered with correct arg");
67 function test_Layer_Vector_addFeatures(t) {
70 var layer = new OpenLayers.Layer.Vector(name);
72 var point = new OpenLayers.Geometry.Point(-111.04, 45.68);
73 var pointFeature = new OpenLayers.Feature.Vector(point);
75 layer.preFeatureInsert = function(feature) {
76 t.ok(feature == pointFeature, "OpenLayers.Layer.Vector.addFeatures calls preFeatureInsert with the right arg");
78 layer.onFeatureInsert = function(feature) {
79 t.ok(feature == pointFeature, "OpenLayers.Layer.Vector.addFeatures calls onFeatureInsert with the right arg");
81 layer.events.register('beforefeatureadded', null, function(obj) {
82 t.ok(pointFeature == obj.feature, "OpenLayers.Layer.Vector.addFeatures triggers beforefeatureadded with correct feature passed to callback");
84 layer.events.register('featureadded', null, function(obj) {
85 t.ok(pointFeature == obj.feature, "OpenLayers.Layer.Vector.addFeatures triggers featureadded with correct feature passed to callback");
87 layer.events.register('featuresadded', null, function(obj) {
88 t.ok(pointFeature == obj.features[0], "OpenLayers.Layer.Vector.addFeatures triggers featuresadded with correct features passed to callback");
91 layer.addFeatures([pointFeature]);
93 t.eq(layer.features.length, 1, "OpenLayers.Layer.Vector.addFeatures adds something to the array");
94 t.ok(layer.features[0] == pointFeature, "OpenLayers.Layer.Vector.addFeatures returns an array of features");
96 layer.preFeatureInsert = function(feature) {
97 t.fail("OpenLayers.Layer.Vector.addFeatures calls preFeatureInsert while it must not");
99 layer.onFeatureInsert = function(feature) {
100 t.fail("OpenLayers.Layer.Vector.addFeatures calls onFeatureInsert while it must not");
102 layer.events.register('beforefeatureadded', null, function(obj) {
103 t.fail("OpenLayers.Layer.Vector.addFeatures triggers beforefeatureadded while it must not");
105 layer.events.register('featureadded', null, function(obj) {
106 t.fail("OpenLayers.Layer.Vector.addFeatures triggers featureadded while it must not");
108 layer.events.register('featuresadded', null, function(obj) {
109 t.fail("OpenLayers.Layer.Vector.addFeatures triggers featuresadded while it must not");
112 layer.addFeatures([pointFeature], {silent: true});
114 var extent = layer.getDataExtent();
115 t.eq(extent.toBBOX(), "-111.04,45.68,-111.04,45.68", "extent from getDataExtent is correct");
118 function test_Layer_Vector_getDataExtent(t) {
120 var layer = new OpenLayers.Layer.Vector(name);
122 var point = new OpenLayers.Geometry.Point(-111.04, 45.68);
123 var pointFeature = new OpenLayers.Feature.Vector(point);
124 layer.addFeatures([pointFeature]);
125 var point = new OpenLayers.Geometry.Point(-111.04, 5.68);
126 var pointFeature = new OpenLayers.Feature.Vector(point);
127 layer.addFeatures([pointFeature]);
128 var extent = layer.getDataExtent();
129 t.ok(extent.toBBOX() != layer.features[0].geometry.getBounds().toBBOX(), "extent from getDataExtent doesn't clobber first feature");
132 function test_Layer_Vector_removeFeatures(t) {
135 var layer = new OpenLayers.Layer.Vector(name);
137 var point1 = new OpenLayers.Geometry.Point(-111.04, 45.68);
138 var pointFeature1 = new OpenLayers.Feature.Vector(layer, point1);
139 var point2 = new OpenLayers.Geometry.Point(-111.14, 45.78);
140 var pointFeature2 = new OpenLayers.Feature.Vector(layer, point2);
142 layer.addFeatures([pointFeature1, pointFeature2]);
143 var features = layer.removeFeatures([pointFeature1]);
145 t.ok(layer.features.length == 1, "OpenLayers.Layer.Vector.removeFeatures removes a feature from the features array");
146 layer.addFeatures([pointFeature1.clone(), pointFeature2.clone()]);
147 layer.selectedFeatures.push(layer.features[0]);
148 layer.removeFeatures(layer.features[0]);
149 t.eq(layer.selectedFeatures, [], "Remove features removes selected features");
150 var features = layer.removeFeatures(layer.features);
152 t.ok(layer.features.length == 0,
153 "OpenLayers.Layer.Vector.removeFeatures(layer.features) removes all feature from the features array");
156 layer.events.register('beforefeatureremoved', null, function(obj) {
157 t.ok(pointFeature1 == obj.feature,
158 "OpenLayers.Layer.Vector.removeFeatures triggers beforefeatureremoved with correct feature passed to callback");
160 layer.events.register('featureremoved', null, function(obj) {
161 t.ok(pointFeature1 == obj.feature,
162 "OpenLayers.Layer.Vector.removeFeatures triggers featureremoved with correct feature passed to callback");
164 layer.events.register('featuresremoved', null, function(obj) {
165 t.ok(pointFeature1 == obj.features[0],
166 "OpenLayers.Layer.Vector.removeFeatures triggers featuresremoved with correct features passed to callback");
168 layer.addFeatures([pointFeature1]);
169 layer.removeFeatures([pointFeature1]);
170 layer.addFeatures([pointFeature1]);
171 layer.removeFeatures(layer.features);
174 layer.events.register('beforefeatureremoved', null, function(obj) {
175 t.fail("OpenLayers.Layer.Vector.removeFeatures triggers beforefeatureremoved while it must not");
177 layer.events.register('featureremoved', null, function(obj) {
178 t.fail("OpenLayers.Layer.Vector.removeFeatures triggers featureremoved while it must not");
180 layer.events.register('featuresremoved', null, function(obj) {
181 t.fail("OpenLayers.Layer.Vector.removeFeatures triggers featuresremoved while it must not");
183 layer.addFeatures([pointFeature1]);
184 layer.removeFeatures([pointFeature1], {silent: true});
187 function test_Layer_Vector_drawFeature(t) {
189 var layer = new OpenLayers.Layer.Vector("Test Layer", {isBaseLayer: true});
190 var map = new OpenLayers.Map('map', {
191 maxExtent: new OpenLayers.Bounds(-100, -100, 100, 100)
194 var geometry = new OpenLayers.Geometry.Point(10, 10);
195 var feature = new OpenLayers.Feature.Vector(geometry);
199 // Bogus layer renderer needs some methods
200 // for functional tests.
203 drawFeature: function(feature, style) {
207 root: document.createElement("div"),
208 destroy: function() { },
209 eraseFeatures: function() {},
210 setExtent: function() {}
214 layer.drawFeature(feature);
215 t.ok(geometry.equals(f.geometry),
216 "calls layer.renderer.drawFeature() with feature.geometry");
218 feature.style = {foo: "bar"};
219 layer.drawFeature(feature);
220 t.eq(feature.style, s,
221 "calls layer.renderer.drawFeature() with feature.style");
223 feature.style = null;
224 layer.style = {foo: "bar"};
225 layer.drawFeature(feature);
226 t.eq(layer.style.foo, s.foo,
227 "given null feature style, uses layer style");
229 feature.style = {foo1: "bar1"};
230 layer.style = {foo2: "bar2"};
231 var customStyle = {foo: "bar"};
232 layer.drawFeature(feature, customStyle);
233 t.eq(customStyle.foo, s.foo,
234 "given a custom style, renders with that");
236 // the real renderer's drawFeature method is tested in Renderer.html
237 layer.renderer.drawFeature = function(feature) {
238 return(feature.geometry.getBounds().intersectsBounds(map.getExtent()));
240 // reset the drawn to null as if the layer had never been rendered
243 layer.drawFeature(feature);
244 t.ok(true, "Trying to draw a feature on an not drawn layer doesn't throw any error.");
246 layer.addFeatures([feature]);
248 map.setCenter(new OpenLayers.Bounds(0, 0, 0, 0), 6);
249 t.ok(layer.unrenderedFeatures[feature.id], "Did not render feature outside the viewport.");
250 map.panTo(new OpenLayers.LonLat(10, 10));
251 t.ok(!layer.unrenderedFeatures[feature.id], "Rendered feature inside the viewport.");
256 function test_deleted_state(t) {
259 var map = new OpenLayers.Map("map");
260 var layer = new OpenLayers.Layer.Vector(null, {
264 var feature = new OpenLayers.Feature.Vector(
265 new OpenLayers.Geometry.Point(10, 10)
269 drawFeature: function(f, s) {
275 destroy: function() {}
278 // draw feature with no state
279 layer.drawFeature(feature);
280 t.ok(log.feature === feature, "[no state] drawFeature called with correct feature");
281 t.ok(log.style.display !== "none", "[no state] drawFeature called with style display not none");
283 // draw feature with delete style
284 feature.state = OpenLayers.State.DELETE;
285 layer.drawFeature(feature);
286 t.ok(log.feature === feature, "[delete] drawFeature called with correct feature");
287 t.eq(log.style.display, "none", "[delete] drawFeature called with style display none");
289 // undelete the feature and redraw
290 delete feature.state;
291 delete feature.renderIntent;
292 layer.drawFeature(feature);
293 t.ok(log.feature === feature, "[undelete] drawFeature called with correct feature");
294 t.ok(log.style.display !== "none", "[undelete] drawFeature called with style display not none");
296 // change deleted style
297 layer.styleMap.styles["delete"] = new OpenLayers.Style({fillOpacity: 0.1});
299 // draw feature with delete style
300 feature.state = OpenLayers.State.DELETE;
301 layer.drawFeature(feature);
302 t.ok(log.feature === feature, "[draw deleted] drawFeature called with correct feature");
303 t.ok(log.style.display !== "none", "[draw deleted] drawFeature called with style display not none");
304 t.eq(log.style.fillOpacity, 0.1,"[draw deleted] drawFeature called with correct fill opacity");
309 function test_Layer_Vector_eraseFeatures(t) {
311 var layer = new OpenLayers.Layer.Vector("Test Layer");
312 var map = new OpenLayers.Map('map');
314 var geometry = new OpenLayers.Geometry.Point(10, 10);
315 var feature = new OpenLayers.Feature.Vector(geometry);
319 eraseFeatures: function(features) {
322 destroy: function() { }
325 layer.eraseFeatures([feature]);
326 t.ok(f, "calls layer.renderer.eraseFeatures");
327 t.ok(geometry.equals(f.geometry),
328 "calls layer.renderer.eraseFeatures() given an array of features");
331 function test_Layer_Vector_destroyFeatures (t) {
333 layer = new OpenLayers.Layer.Vector(name);
334 var map = new OpenLayers.Map('map');
337 for (var i = 0; i < 5; i++) {
338 features.push(new OpenLayers.Feature.Vector(
339 new OpenLayers.Geometry.Point(0,0)));
341 layer.addFeatures(features);
342 t.eq(layer.features.length, 5, "addFeatures adds 5 features");
343 layer.selectedFeatures.push(features[0]);
344 layer.destroyFeatures();
345 t.eq(layer.features.length, 0, "destroyFeatures triggers removal");
346 t.eq(layer.selectedFeatures, [], "Destroy features removes selected features");
348 for (var i = 0; i < 5; i++) {
349 features.push(new OpenLayers.Feature.Vector(
350 new OpenLayers.Geometry.Point(0,0)));
352 layer.addFeatures(features);
353 layer.selectedFeatures.push(features[0]);
354 layer.selectedFeatures.push(features[1]);
355 layer.destroyFeatures([features[0], features[1]]);
356 t.eq(layer.features.length, 3, "destroyFeatures removes appropriate features");
357 t.eq(layer.selectedFeatures, [], "destroyFeatures removes appropriate selected features");
360 function test_Layer_Vector_destroy (t) {
363 var options = {protocol: new OpenLayers.Protocol(),
364 strategies: [new OpenLayers.Strategy(), new OpenLayers.Strategy()]}
365 var layer = new OpenLayers.Layer.Vector(name, options);
366 var map = new OpenLayers.Map('map');
369 t.eq(layer.map, null, "layer.map is null after destroy");
370 t.eq(layer.getFeatureFromEvent({'target':'map'}), null,
371 "getFeatureIdFromEvent doesn't cause an error when called on layer which has been destroyed.");
373 t.eq(layer.protocol, null, "layer.protocol is null after destroy");
374 t.eq(layer.strategies, null, "layer.strategies is null after destroy");
376 // test that we can call layer.destroy a second time without trouble
380 t.ok(true, "layer.destroy called twice without any issues");
382 t.fail("calling layer.destroy twice triggers exception: " + err + " in " + err.fileName + " line " + err.lineNumber);
387 function test_Layer_Vector_externalGraphic(t) {
389 var layer = new OpenLayers.Layer.Vector("Test Layer", {isBaseLayer: true});
390 var renderer = layer.renderer;
391 var map = new OpenLayers.Map('map');
392 map.addLayers([layer]);
396 var geometry = new OpenLayers.Geometry.Point(geometryX, geometryY);
397 var feature = new OpenLayers.Feature.Vector(geometry);
399 map.zoomToMaxExtent();
401 var customStyle1 = new Object({
402 externalGraphic: 'test.png',
405 var customStyle2 = new Object({
406 externalGraphic: 'test.png',
409 var customStyle3 = new Object({
410 externalGraphic: 'test.png',
413 var customStyle4 = new Object({
414 externalGraphic: 'test.png',
418 var customStyle5 = new Object({
419 externalGraphic: 'test.png',
423 var customStyle6 = new Object({
424 externalGraphic: 'test.png',
431 var root = renderer.vectorRoot;
432 if (layer.renderer.CLASS_NAME == 'OpenLayers.Renderer.SVG') {
433 feature.style = customStyle1;
434 layer.drawFeature(feature);
435 t.eq(root.firstChild.getAttributeNS(null, 'width'),
436 (2*customStyle1.pointRadius).toString(),
437 "given a pointRadius, width equals 2*pointRadius");
438 t.eq(root.firstChild.getAttributeNS(null, 'height'),
439 (2*customStyle1.pointRadius).toString(),
440 "given a pointRadius, height equals 2*pointRadius");
441 feature.style = customStyle2;
442 layer.drawFeature(feature);
443 t.eq(root.firstChild.getAttributeNS(null, 'width'),
444 root.firstChild.getAttributeNS(null, 'height'),
445 "given a graphicWidth, width equals height");
446 t.eq(root.firstChild.getAttributeNS(null, 'width'),
447 customStyle2.graphicWidth.toString(),
448 "width is set correctly");
449 feature.style = customStyle3;
450 layer.drawFeature(feature);
451 t.eq(root.firstChild.getAttributeNS(null, 'height'),
452 root.firstChild.getAttributeNS(null, 'width'),
453 "given a graphicHeight, height equals width");
454 t.eq(root.firstChild.getAttributeNS(null, 'height'),
455 customStyle3.graphicHeight.toString(),
456 "height is set correctly");
457 feature.style = customStyle4;
458 layer.drawFeature(feature);
459 t.eq(root.firstChild.getAttributeNS(null, 'height'),
460 customStyle4.graphicHeight.toString(),
461 "given graphicHeight and graphicWidth, both are set: height");
462 t.eq(root.firstChild.getAttributeNS(null, 'width'),
463 customStyle4.graphicWidth.toString(),
464 "given graphicHeight and graphicWidth, both are set: width");
465 feature.style = customStyle5;
466 layer.drawFeature(feature);
467 t.eq(root.firstChild.getAttributeNS(null, 'style'),
468 'opacity: '+customStyle5.graphicOpacity.toString()+((OpenLayers.Util.getBrowserName() == "opera" || OpenLayers.Util.getBrowserName() == "safari") ? "" : ';'),
469 "graphicOpacity correctly set");
470 feature.style = customStyle6;
471 layer.drawFeature(feature);
472 var x = geometryX / renderer.getResolution() + renderer.left;
473 var y = geometryY / renderer.getResolution() - renderer.top;
474 // SVG setStyle() gets x and y using getAttributeNS(), which returns
475 // a value with only 3 decimal digits. To mimic this we use toFixed(3) here
478 // toFixed() returns a string
481 t.eq(root.firstChild.getAttributeNS(null, 'x'),
482 (x + customStyle6.graphicXOffset).toFixed().toString(),
483 "graphicXOffset correctly set");
484 t.eq(root.firstChild.getAttributeNS(null, 'y'),
485 (-y + customStyle6.graphicYOffset).toFixed().toString(),
486 "graphicYOffset correctly set");
488 if (layer.renderer.CLASS_NAME == 'OpenLayers.Renderer.VML') {
489 feature.style = customStyle1;
490 layer.drawFeature(feature);
491 t.eq(root.firstChild.style.width,
492 (2*customStyle1.pointRadius).toString()+'px',
493 "given a pointRadius, width equals 2*pointRadius");
494 t.eq(root.firstChild.style.height,
495 (2*customStyle1.pointRadius).toString()+'px',
496 "given a pointRadius, height equals 2*pointRadius");
497 feature.style = customStyle2;
498 layer.drawFeature(feature);
499 t.eq(root.firstChild.style.width,
500 root.firstChild.style.height,
501 "given a graphicWidth, width equals height");
502 t.eq(root.firstChild.style.width,
503 customStyle2.graphicWidth.toString()+'px',
504 "width is set correctly");
505 feature.style = customStyle3;
506 layer.drawFeature(feature);
507 t.eq(root.firstChild.style.height,
508 root.firstChild.style.width,
509 "given a graphicHeight, height equals width");
510 t.eq(root.firstChild.style.height,
511 customStyle3.graphicHeight.toString()+'px',
512 "height is set correctly");
513 feature.style = customStyle4;
514 layer.drawFeature(feature);
515 t.eq(root.firstChild.style.height,
516 customStyle4.graphicHeight.toString()+'px',
517 "given graphicHeight and graphicWidth, both are set: height");
518 t.eq(root.firstChild.style.width,
519 customStyle4.graphicWidth.toString()+'px',
520 "given graphicHeight and graphicWidth, both are set: width");
521 feature.style = customStyle5;
522 layer.renderer.clear();
523 layer.drawFeature(feature);
524 var fill = root.firstChild.getElementsByTagName("v:fill")[0];
527 opacity = fill.getAttribute('opacity');
529 if(opacity === undefined) {
530 fill = root.firstChild.getElementsByTagName("fill")[0];
531 opacity = fill.getAttribute('opacity');
534 customStyle5.graphicOpacity,
535 "graphicOpacity correctly set");
536 feature.style = customStyle6;
537 layer.drawFeature(feature);
538 var x = geometryX / renderer.getResolution();
539 var y = geometryY / renderer.getResolution();
540 t.eq(root.firstChild.style.left,
541 (x + customStyle6.graphicXOffset).toFixed().toString()+'px',
542 "graphicXOffset correctly set");
544 t.eq(root.firstChild.style.top,
545 (y - (customStyle6.graphicYOffset+parseInt(root.firstChild.style.height))).toFixed().toString()+'px',
546 "graphicYOffset correctly set");
554 <div id="map" style="width:500px;height:550px"></div>