Ticket #2077 (new feature)

Opened 5 years ago

Last modified 3 years ago

Standardise CSS styling of all OL Controls, and give appropriate map controls a CSS style to prevent them printing

Reported by: CharlesHarrison Owned by:
Priority: major Milestone: 2.13 Release
Component: Control Version: 2.8 RC2
Keywords: standardise displayClass CSS disable print Cc:
State:

Description

As per title, certain controls have only to do with users control of the map, serve no useful function being printed, and when they are printed hide map data that may be useful. Examples would be: Button, EditingToolbar, LayerSwitcher, MouseToolbar, NavigationHistory, OverviewMap ( the +- button for it, arguably the overview itself should print if the map is printed while it is being displayed), PanZoom(Bar), ZoomBox.

These should be given a CSS style to prevent them being printed over the top of the map, for example (this just happens to be the one I use on my site, I'm not saying that these would necessarily be best settings for any, let alone all, of the above controls):

@media print { .noprint { display:none; margin:0; padding:0; line-height:0; } }

Change History

  Changed 4 years ago by rdewit

  • keywords foss4g09 added

in reply to: ↑ description ; follow-up: ↓ 3   Changed 4 years ago by kotei

Replying to CharlesHarrison:

As per title, certain controls have only to do with users control of the map, serve no useful function being printed, and when they are printed hide map data that may be useful. Examples would be: Button, EditingToolbar, LayerSwitcher, MouseToolbar, NavigationHistory, OverviewMap ( the +- button for it, arguably the overview itself should print if the map is printed while it is being displayed), PanZoom(Bar), ZoomBox. These should be given a CSS style to prevent them being printed over the top of the map, for example (this just happens to be the one I use on my site, I'm not saying that these would necessarily be best settings for any, let alone all, of the above controls): {{{ @media print { .noprint { display:none; margin:0; padding:0; line-height:0; } } }}}

In the Print.html page you can write like this: <style media=print>

span{display:none;}

</style>

<span id="print" class="printbt">

<input type=button onClick="window.print();" class="searchbutton" value="Print Map"/>

</span>

Maybe you can Coding like this.Write some codes in the Tag <span>,then display:none.You do not need to specify each css.

in reply to: ↑ 2 ; follow-up: ↓ 4   Changed 4 years ago by CharlesHarrison

Replying to kotei:

In the Print.html page you can write like this: <style media=print> span{display:none;} </style> <span id="print" class="printbt"> <input type=button onClick="window.print();" class="searchbutton" value="Print Map"/> </span> Maybe you can Coding like this.Write some codes in the Tag <span>,then display:none.You do not need to specify each css.


I already have suitable noprint styles defined for the non-map content over my entire site. What you suggest above is therefore redundant. Worse still, it's counter-productive, because every span on the page would then fail to print, even those in non-map content that should.

What's needed is suitable styles for the map controls.

Incidentally, not all of the controls seem to respect and use the displayClass attribute. Perhaps that could be fixed at the same time.

in reply to: ↑ 3   Changed 4 years ago by CharlesHarrison

  • keywords add displayClass added
  • priority changed from minor to major

Replying to CharlesHarrison:

What's needed is suitable styles for the map controls. Incidentally, not all of the controls seem to respect and use the displayClass attribute. Perhaps that could be fixed at the same time.

As there doesn't seem much likelihood of movement on this in the near future, here's a hack that forces many of the common controls to respect the displayClass option, while also allowing semi-opaque backgrounds for greater readability. However, note that not all browsers will print a semi-opaque background as such, they may print it solid, or make some other mistake:

//	TitleControl
//	============
//
//	Can either:
//
//	Display any valid HTML on the map, with the following syntax:
//
//		new TitleControl( /* Object whose properties are from the following options */ )
//
//	{ html: /* The HTML to be diplayed */ }
//		The HTML can also be set by calling setHTML( html ).
//	{ displayClass: /* A style class for the control as a whole */ }
//		If neither of the additional options below are specified, this is expected to be the
//		entire styling for the control, but if either of the options below is specified, then
//		this is probably going to be just styling to position the control in the map viewport.
//	{ backClass: /* A style class for the background */ }
//		The main purpose of putting the background in a different div is that this allows it to
//		be semi-opaque without making the HTML content of the control also semi-opaque.  This
//		makes the control more visible on the map.
//	{ foreClass: /* A style class for the HTML foreground content */ }
//		This can be such things text alignment, font size, weight, and colour, etc.
//
//	Note that extra seperate child divs for the foreground and background are only created if
//	either or both of the relevant style classes are specified, otherwise just the usual one
//	div is created to house the control.
//
//	Or:
//
//	Display an OpenLayers control, forcing styling as above, even where the OL control doesn't
//	natively support the displayClass option, with the following syntax:
//
//		new TitleControl( new OpenLayers.Control.XXX( /* Usual parameters for the control */ ), /* TitleControl options */ )
//
//	Note that this means that potentially any existing OL control can be positioned anywhere
//	and given a semi-opaque background simply by using CSS  -  I haven't actually tried them all
//	but MousePosition, Attribution, Scale, and ScaleLine all work in this arrangememt.

var	TitleControl = OpenLayers.Class
	(
		OpenLayers.Control,
		{
			displayClass:	null,
			foreClass:		null,
			backClass:		null,
			tDiv:			null,
			bDiv:			null,
			fDiv:			null,

			html: 			"",

			initialize:		function( olControl, options )
								{
								if( olControl.CLASS_NAME )
									{
									this.myDraw = this.draw;
									this.myDC = this.displayClass;
									OpenLayers.Util.extend( this, olControl );
									try{this.events.destroy();}catch(e){}
									try{olControl.destroy();}catch(e){}
									this.olDraw = this.draw;
									this.olDC = this.displayClass;
									this.draw = this.myDraw;
									this.displayClass = this.myDC;
									}
								else
									options = olControl;
								OpenLayers.Control.prototype.initialize.apply( this, [options] );
								this.tDiv = this.div ? this.div : OpenLayers.Util.createDiv( this.id );
								if( this.displayClass && (this.tDiv.className != this.displayClass) )
									this.tDiv.className = this.displayClass;
								if( this.backClass || this.foreClass )
									{
									this.bDiv = OpenLayers.Util.createDiv( this.id + "b" );
									if( this.backClass )
										this.bDiv.className = this.backClass;
									this.bDiv.innerHTML = "&nbsp;";
									this.tDiv.appendChild( this.bDiv );
									this.fDiv = OpenLayers.Util.createDiv( this.id + "f" );
									if( this.foreClass )
										this.fDiv.className = this.foreClass;
									this.fDiv.innerHTML = "";
									this.tDiv.appendChild( this.fDiv );
									}
								},

			destroy:		function()
								{
							for( var t in this.map.events.listeners )
								for( var l = this.map.events.listeners[t].length - 1; l >= 0; l -= 1 )
								if( this == this.map.events.listeners[t][l].obj )
										this.map.events.unregister( t, this.map.events.listeners[t][l].obj, this.map.events.listeners[t][l].func );
						    if( this.tDiv )
							this.div = this.tDiv;
								if( this.bDiv )
									{
									this.bDiv.innerHTML = "";
									this.tDiv.removeChild( this.bDiv );
									this.bDiv = undefined;
									}
								if( this.fDiv )
									{
									this.fDiv.innerHTML = "";
									this.tDiv.removeChild( this.fDiv );
									this.fDiv = undefined;
									}
								this.div.innerHTML = "";
								OpenLayers.Control.prototype.destroy.apply( this, arguments );
								},

			draw:			function( px )
								{
								this.div = this.fDiv ? this.fDiv : this.tDiv;
								if( this.olDraw )
									{
									if( this.olDC )
										this.displayClass = this.olDC;
									this.olDraw( px )
									}
								else
									{
									OpenLayers.Control.prototype.draw.apply( this, arguments );
									this.setHTML();
									}
								return this.tDiv;
								},

			setHTML:		function( html )
								{
								if( html && (this.html != html) )
									this.html = html;
								if( this.div.innerHTML != this.html )
									this.div.innerHTML = this.html;
								},

			CLASS_NAME:		"TitleControl"
		}
	);

  Changed 4 years ago by CharlesHarrison

  • keywords standardise CSS added; add foss4g09 removed
  • summary changed from Give appropriate map controls a CSS style to hide them when printing to Standardise CSS styling of all OL Controls, and give appropriate map controls a CSS style to prevent them printing

Generally OL Controls currently are a hotch-potch, probably because they have been written by different people working to to different standards for different versions.

Particularly:

1) Although the displayClass property is defined in OpenLayers.Control, most of the subclasses ignore it.
2) The functions that draw/update the content of the controls all have different names.
3) Controls that have no meaning on a printout because they are solely to do with manipulating the map nevertheless usually print.

Controls need to be standardised on the displayClass property as the primary means of positioning and styling. Functions to update the controls need to have consistent names. Those controls that are solely to do with manipulating the map and have no meaning on a printout need to be prevented from printing.

I suggest adapting OpenLayers.Control along the lines of the above 'hack' would be a good starting point, though, of course, much more would be involved.

To demonstrate the sort of problems that occur, and how an arrangement such as the above can be used as a 'fix', at least until the job can be done properly if not as part of a permanent cure, contrast the problems here ...

 http://www.macfh.co.uk/Test/GoogleOLControls.html

... with ...

 http://www.macfh.co.uk/Test/Google_with_OpenLayers.html

  Changed 3 years ago by CharlesHarrison

Replying to CharlesHarrison:

3) Controls that have no meaning on a printout because they are solely to do with manipulating the map nevertheless usually print.

The fix for this is easy - append to style.css something like the following (the Overview Map buttons, but not the Overview Map itself, need to be included, but I haven't tried to do that in this brief test):

@media print { .olControlLayerSwitcher, .olControlLayerSwitcher *, .olControlNavToolbar, .olControlNavToolbar *, .olControlPanPanel, .olControlPanPanel *, .olControlPanZoomBar, .olControlPanZoomBar *, .olControlPanel, .olControlPanel *, .olControlZoomPanel, .olControlZoomPanel *

{ display:none; }

}

Further issues have come to light regarding the Panel control.

1) Instead of, as it should, allowing each control in the panel (hereinafter referred to as a sub-control) to create its own div, in a manner appropriate to that sub-control, it creates empty divs for each, thus throwing away any special features or attributes that the control may have created for itself. The Panel needs to let the sub-control draw itself, and then observe the clicks on the div that the sub-control has created in order to create the functionality for the panel.

2) Secondly, the values and testing for the following constants show lack of forethought. It's common for such systems to create bitwise flags using the values 1,2,4 etc, so that characteristics can be combined but still tested for individually, and that should have been done here - what if one wants a radio-button style functionality (TYPE_TOOL) but still trigger a function when a button is clicked (TYPE_BUTTON)?

/**

  • Constant: OpenLayers.Control.TYPE_BUTTON */

OpenLayers.Control.TYPE_BUTTON = 1;

/**

  • Constant: OpenLayers.Control.TYPE_TOGGLE */

OpenLayers.Control.TYPE_TOGGLE = 2;

/**

  • Constant: OpenLayers.Control.TYPE_TOOL */

OpenLayers.Control.TYPE_TOOL = 3;

3) Thirdly by relying on the background-image CSS property to display the buttons, they are guaranteed to be invisible under some situations. What if a user needs or simply prefers to force all the colours on every site that (s)he visits to be either white on black or black on white? Having operating system desktop colours that have white text on a black background shows that probably the majority of sites on the web currently have broken colour schemes, so needing to fix them in the browser is not uncommon. This can be done in FF, for example, by choosing Tools, Options, Content, Colours, select Use system colours, unselect Allow pages to choose their own colours. In this situation, background images do not show, and the panel buttons are all invisible!

They need to be put into an image tag like conventional images, but of course they can't be, because even if Button is sub-classed to do it, Panel throws all the work away :-(

Sigh!

Also, as previously demoed, certain controls need to be given sensible dimensions so that they don't trap mouse events over more of the map than they themselves need at a minimum to function properly.

Note: See TracTickets for help on using tickets.