Copyright (c) 2002, DM Solutions Group Inc. * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ /* * MODIFICATIONS (C) 2005, Andreas Hocevar * - bugfix: use tolerance from cwc2 call (and not 3!) * - bugfix: use correct variable $this->mszOnMouseOut (not $this->onMouseOut) * for $onmouseout and fix semicolon typo in $onmouseover definiton. * - bugfix: set default onmouseover and onmouseout to correct names * (i.e. MapTipContent and MapTip clear instead of MapTipsContent and * MapTipsClear). * - add feature: if keyword "LinkUniqueID" (case insensitive) is found in the * LINKURL attribute, it is replaced by the current link-id. This is useful * if your LinkURL looks more like "javascript:openURL(12345, 'foo')" that * "http://www.foo.bar/index.php?id=12345". * - add feature: new LINKTARGET attribute. If not set, "_blank" is used to * keep compatibility with previous versions. If LINKTARGET attribute is set * to "", it will be omitted in the according hfres. */ include_once(dirname(__FILE__)."/../Widget.php"); include_once(dirname(__FILE__)."/../Button.php"); include_once(dirname(__FILE__)."/../Popup.php"); include_once(dirname(__FILE__)."/../LayerAttributes.php"); /** * MapTips Widget * * @desc A widget that draws dynamic MapTips on the MapImage. Uses an * imagemap to dynamically position a hidden layer with relevant * information. */ class MapTips extends CWCWidget { var $moButton; var $moPopup; /* default settings for the widget params */ var $mszDefaultText = " "; // Default text for noon-active maptip var $mnTolerance = 4; // Imagemap point tolerance for each AREA entry var $mszLayer = ''; var $maszAttributes = array(); var $mszLinkURL = ''; // URL to go to var $mszLinkTarget = '_blank'; // Link target var $mszLinkUniqueID = ''; // unique location id to append to url var $mszTitleClass = 'label'; var $mszTitleStyle = ''; var $mszLabelClass = 'label'; var $mszLabelStyle = ''; /* internal vars */ var $mszImageMapName = 'maptips_imagemap'; var $mszMapTipsDiv = 'maptips_container'; var $mszTransparentMapDiv = 'maptips_overlay'; var $mszTransparentMapImage = 'maptips_image'; var $mszPixelGif = ''; var $mszOnMouseOver = 'MapTipsOver'; var $mszOnMouseOut = 'MapTipsOut'; var $mszOnClick = ''; /** * MapTips * * @desc Constructor method for the MapTips widget. */ function MapTips() { /* invoke constructor of parent */ parent::CWCWidget(); /* set the description for this widget */ $this->szWidgetDescription = <<moPopup = new CWCPopup( $this ); $this->moPopup->mszLink = $_SESSION['gszCoreWebPath']."/widgets/MapTips/MapTipsPopup.phtml"; $this->moButton = new CWCButton( $this ); /* declare the required OR allowable cwc2 parameters for this widget */ $this->maAttributes["LAYER"] = new StringAttribute( "LAYER", false ); $this->maAttributes["ATTRIBUTES"] = new StringAttribute( "ATTRIBUTES", false ); $this->maAttributes["DEFAULTTEXT"] = new StringAttribute( "DEFAULTTEXT", false ); $this->maAttributes["TOLERANCE"] = new IntegerAttribute( "TOLERANCE", false ); $this->maAttributes["LINK"] = new BooleanAttribute( "LINK", false ); $this->maAttributes["LINKURL"] = new StringAttribute( "LINKURL", false ); $this->maAttributes["LINKTARGET"] = new StringAttribute( "LINKTARGET", false ); $this->maAttributes["LINKUNIQUEID"] = new StringAttribute( "LINKUNIQUEID", false ); $this->maAttributes["MAPTIPSDIV"] = new StringAttribute( "MAPTIPSDIV", true ); $this->maAttributes["TITLECLASS"] = new StringAttribute( "TITLECLASS", false ); $this->maAttributes["TITLESTYLE"] = new StringAttribute( "TITLESTYLE", false ); $this->maAttributes["LABELCLASS"] = new StringAttribute( "LABELCLASS", false ); $this->maAttributes["LABELSTYLE"] = new StringAttribute( "LABELSTYLE", false ); $this->maAttributes["ONMOUSEOVER"] = new StringAttribute( "ONMOUSEOVER", false ); $this->maAttributes["ONMOUSEOUT"] = new StringAttribute( "ONMOUSEOUT", false ); $this->maAttributes["ONCLICK"] = new StringAttribute( "ONCLICK", false ); $this->mnMaturityLevel = MATURITY_BETA; } /** * InitDefaults * */ function InitDefaults() { parent::InitDefaults(); $this->moButton->InitDefaults(); //this widget should never belong to a toolset $this->maParams["TOOLSET"] = ""; $this->moButton->SetOnClick('clickMapTipsPopup'); $this->moPopup->InitDefaults(); /* init the params if user set them */ if (isset($this->maParams["LAYER"])) $this->mszLayer = $this->maParams["LAYER"]; if (isset($this->maParams["ATTRIBUTES"])) $this->maszAttributes = explode( ",", $this->maParams["ATTRIBUTES"] ); if (isset($this->maParams["DEFAULTTEXT"])) $this->mszDefaultText = $this->maParams["DEFAULTTEXT"]; if (isset($this->maParams["TOLERANCE"])) $this->mnTolerance = $this->maParams["TOLERANCE"]; if (isset($this->maParams["LINK"])) { $this->mszLink = $this->maParams["LINK"]; if (isset($this->maParams["LINKURL"])) $this->mszLinkURL = $this->maParams["LINKURL"]; if (isset($this->maParams["LINKTARGET"])) $this->mszLinkTarget = $this->maParams["LINKTARGET"]; if (isset($this->maParams["LINKUNIQUEID"])) $this->mszLinkUniqueID = $this->maParams["LINKUNIQUEID"]; } if (isset($this->maParams['ONMOUSEOVER']) && isset($this->maParams['ONMOUSEOUT'])) { $this->mszOnMouseOver = $this->maParams['ONMOUSEOVER']; $this->mszOnMouseOut = $this->maParams['ONMOUSEOUT']; } if (isset($this->maParams["ONCLICK"])) $this->mszOnClick = $this->maParams["ONCLICK"]; $this->mszImageMapName .= $this->mnId; $this->mszTransparentMapImage .= $this->mnId; if (isset($this->maParams["MAPTIPSDIV"])) $this->mszMapTipsDiv = $this->maParams["MAPTIPSDIV"]; if (isset($this->maParams["TITLECLASS"])) $this->mszTitleClass = $this->maParams["TITLECLASS"]; if (isset($this->maParams["TITLESTYLE"])) $this->mszTitleStyle = $this->maParams["TITLESTYLE"]; if (isset($this->maParams["LABELCLASS"])) $this->mszLabelClass = $this->maParams["LABELCLASS"]; if (isset($this->maParams["LABELSTYLE"])) $this->mszLabelStyle = $this->maParams["LABELSTYLE"]; $this->mszPixelGif = $_SESSION['gszCoreWebPath'].'/skins/default/images/a_pixel.gif'; } function GetJavascriptOnLoadFunctions() { $aReturn = $this->moButton->GetJavascriptOnLoadFunctions(); if ($this->mszLayer != '') { /* this positions the transparent gif over the map to be used in conjunction with the MapTips. */ /* the gif has an image map associated with it */ $szJsFunctionName = "CWCDHTML_PositionLayerByImage"; $szFunction = "$szJsFunctionName('".$this->mszTransparentMapDiv."', 'mapimage', 'tl', 0, 0 );"; $aReturn[$szJsFunctionName] = $szFunction; } return $aReturn; } /** * DrawPublish() * * @desc draw this widget on the page */ function DrawPublish() { $szResult = ""; if ($this->mszLayer != '') { $szImageMap = $this->GenerateImageMap(); if ($szImageMap !== false) { $szResult .= $szImageMap; $szResult .= "\n\n"; } } /* return the result */ if (!$this->mbVisible) return "".$szResult; if ($this->mbVisible) { $szResult .= $this->moButton->DrawPublish(); } return $szResult; } /** * ParseURL inspects incoming form variables and sets up the * maptips object to generate an image map (which happens in * drawpublish) */ function ParseURL() { //only do this if t if ($this->isVarSet( 'MAPTIPS_LAYER' ) && $this->getVar( 'MAPTIPS_LAYER' ) != "") { $this->mszLayer = $this->getVar( 'MAPTIPS_LAYER' ); $this->maszAttributes = explode( ",", $this->getVar( 'MAPTIPS_ATTRIBUTES' ) ); $this->mszLinkURL = $this->getVar( 'MAPTIPS_URL' ); $this->mszLinkUniqueID = $this->getVar( 'MAPTIPS_UNIQUEID' ); } return true; } /** * GenerateImageMap() * * @desc ImageMap generation */ function GenerateImageMap() { /** * SAMPLE MAPTIP IMAGEMAP LINE OUTPUT * * * * * This is a general client-side imagemap that attaches itself to the * transparent gif inside the maptipscontainer DIV. pix coords from * GetQueryDump() populate the circle locations of the image map. */ $szMap = false; //delete temp WFS layer??? $bDeleteLayer = false; $oMap =& $this->moMapObject->oMap; $oLayer = @$oMap->getLayerByName( $this->mszLayer ); if ($oLayer == null || $oLayer->isVisible() == MS_FALSE) { return $szMap; } $nCount = 0; $szTitleTag = "mszTitleClass != "") { $szTitleTag .= ' class='.$this->mszTitleClass; } if ($this->mszTitleStyle != "") { $szTitleTag .= " style=\"".$this->mszTitleStyle."\""; } $szTitleTag .= ">"; $szLabelTag = "mszLabelClass != "") { $szLabelTag .= ' class='.$this->mszLabelClass; } if ($this->mszLabelStyle != "") { $szLabelTag .= " style=\"".$this->mszLabelStyle."\""; } $szLabelTag .= ">"; if ($oLayer->connectiontype == MS_WMS) { //create a temp WFS layer if possible? $aszAttributes = GetLayerAttributes( $oLayer ); if (count($aszAttributes) > 0 && isset($aszAttributes['onlineresource']) && $aszAttributes['onlineresource'] != '') { $oWFSLayer = ms_newLayerObj( $oMap ); $oWFSLayer->set( "status", MS_ON ); $oWFSLayer->set( "name", "wfs_".$oLayer->name ); $oWFSLayer->set( "connectiontype", MS_WFS ); $oWFSLayer->set( 'connection', $aszAttributes['onlineresource'] ); $oWFSLayer->set( "type", eval( 'return '.$aszAttributes['fields']['LayerType'].';' ) ); $oWFSLayer->set( "tolerance", 5 ); //to get the required SRS we need to get the capabilities first $szSRS = getWFSSRS( $aszAttributes['onlineresource'].'request=getcapabilities', $oLayer->name ); $oWFSLayer->setmetadata( "wfs_srs", $szSRS ); $oWFSLayer->setmetadata( "wfs_typename", $oLayer->name); $oClass = ms_newClassObj( $oWFSLayer ); //todo set class up $oLayer = $oWFSLayer; $bDeleteLayer = true; } } if ($oLayer->type == MS_LAYER_POINT || $oLayer->type == MS_LAYER_LINE || $oLayer->type == MS_LAYER_POLYGON ) { //there is a mapserver bug (569) that stops us from putting //the template on the layer ... it has to go in the classes //instead :( $szMap = "mszImageMapName."\">\n"; $szValues = "new Array("; $szContents = "new Array("; $szSep = ""; for( $j=0; $jmaszAttributes ); $j++) { $szContents .= $szSep."\"[".$this->maszAttributes[$j]."]\""; $szValues .= $szSep."\"".$this->maszAttributes[$j]."\""; $szSep = ","; } $szContents .= ")"; $szValues .= ")"; $href= 'href="javascript:void(0);" '; $onmouseover = 'onmouseover=\''.$this->mszOnMouseOver.'(arguments[0], '.$szContents.', '.$szValues.')\' '; $onmouseout = 'onmouseout=\''.$this->mszOnMouseOut.'(arguments[0],'.$szContents.', '.$szValues.')\' '; $onmousemove = 'onmousemove="CWC2OnMouseMoveFunction(arguments[0])"'; $onclick = ($this->mszOnClick == '')?'':'onclick=\''.$this->mszOnClick.'(arguments[0],'.$szContents.', '.$szValues.')\' '; if ($oLayer->type == MS_LAYER_POINT) { $szTemplate = 'mnTolerance.'" '.$href.$onmouseover.$onmouseout.$onmousemove.$onclick.'>'; } elseif ($oLayer->type == MS_LAYER_LINE) { //we handle lines separately because we need to buffer them ... $szTemplate = '[shpxy xf="," sf="~" proj="image"],'.$szContents.'|'; } elseif ($oLayer->type == MS_LAYER_POLYGON) { $szTemplate = ''; } $szTemplatePath = getSessionSavePath()."maptips_template.html"; $hTemplate = fopen( $szTemplatePath, "w+" ); fwrite( $hTemplate, $szTemplate ); fclose( $hTemplate ); $aszOldTemplates = array(); for ($i=0; $i<$oLayer->numclasses; $i++) { $oClass = $oLayer->getClass( $i ); array_push( $aszOldTemplates, $oClass->template ); $oClass->set( "template", $szTemplatePath ); } $szOldTemplate = $oLayer->template; //need to clear the template on the layer if it is is set ... but there //was no way to do this before 2003/03/09 mapscript //$oLayer->set( "template", null ); @$oLayer->queryByRect( $oMap->extent ); //echo "num results = ".$oLayer->getNumResults()."
"; $szCoords = $oMap->processQueryTemplate( array(), false ); for ($i=0; $i<$oLayer->numclasses; $i++) { $oClass = $oLayer->getClass( $i ); $oClass->set( "template", $aszOldTemplates[$i] ); } //$oLayer->set( "template", $szOldTemplate ); //need to post-process lines into polygon with buffering if ($oLayer->type == MS_LAYER_LINE) { $szNewCoords = ""; $aszLines = explode( "|", $szCoords ); $nLines = count( $aszLines ); for ($i=0; $i < ($nLines); $i++) { $aszLineParts = explode( "~", $aszLines[$i] ); $aszLineCoords = explode( " ", $aszLineParts[0] ); $nLineCoords = count($aszLineCoords); for ($j=0; $j<$nLineCoords -1; $j++ ) { if (trim($aszLineCoords[$j]) == "" ) continue; $aszCoord1 = explode( ",", $aszLineCoords[$j] ); $aszCoord2 = explode( ",", $aszLineCoords[$j + 1] ); if (count( $aszCoord1 ) >= 2 && count( $aszCoord2) >= 2 ) { $anLine = $this->bufferLine( $aszCoord1[0], $aszCoord1[1], $aszCoord2[0], $aszCoord2[1], 2 ); $szBufferedLine = implode( ",", $anLine ); //echo $szBufferedLine."
";MapTipInit(\''.$szContents.'\', \''.$this->mszDynamicDIV.'\', \'dynamic\', [shpxy xf="," transform] ) $szNewCoords .= ''; } } } $szCoords = $szNewCoords; } $szMap .= $szCoords; $szMap .= "
"; $szMap .= "\n"; if ($bDeleteLayer) $oLayer->set( "status", MS_DELETE ); } return $szMap; } /** * calculate a polygon that buffers the line by a given radius * * line algorithm is y = mx + b where m is the slope and b is the y intercept * * */ function bufferLine( $nX1, $nY1, $nX2, $nY2, $nRadius ) { //echo "buffering line from $nX1,$nY1 to $nX2,$nY2 by $nRadius
"; //default result is just the line $anResult = array( $nX1, $nY1, $nX1, $nY1, $nX2, $nY2, $nX2, $nY2 ); //take care of vertical line - infinite slope - div by zero error if ($nY1 == $nY2) { if ($nY1 > $nY2) $dir = -1; else $dir = 1; $anResult[0] = $nX1 - $nRadius; $anResult[1] = $nY1 - $dir * $nRadius; $anResult[2] = $nX1 + $nRadius; $anResult[3] = $nY1 - $dir * $nRadius; $anResult[4] = $nX2 - $nRadius; $anResult[5] = $nY2 + $dir * $nRadius; $anResult[6] = $nX2 + $nRadius; $anResult[7] = $nY2 + $dir * $nRadius; } //take care of horizontal line case because it is easy elseif ($nX1 == $nX2) { if ($nX1 > $nX2) $dir = -1; else $dir = 1; $anResult[0] = $nX1 - $dir *$nRadius; $anResult[1] = $nY1 - $nRadius; $anResult[2] = $nX1 - $dir * $nRadius; $anResult[3] = $nY1 + $nRadius; $anResult[4] = $nX2 + $dir * $nRadius; $anResult[5] = $nY2 - $nRadius; $anResult[6] = $nX2 + $dir * $nRadius; $anResult[7] = $nY2 + $nRadius; } else { //complicated case, sloped line $lrun = $nX2 - $nX1; $lrise = $nY2 - $nY1; $lhyp = sqrt( pow( $lrise, 2 ) + pow( $lrun, 2 ) ); $ex1 = $nX1 - $nRadius*$lrun/$lhyp; $ey1 = $nY1 - $nRadius*$lrise/$lhyp; $ex2 = $nX2 + $nRadius*$lrun/$lhyp; $ey2 = $nY2 + $nRadius*$lrise/$lhyp; $anResult[0] = (int)($ex1 + $nRadius*$lrise/$lhyp); $anResult[1] = (int)($ey1 - $nRadius*$lrun/$lhyp); $anResult[2] = (int)($ex1 - $nRadius*$lrise/$lhyp); $anResult[3] = (int)($ey1 + $nRadius*$lrun/$lhyp); $anResult[4] = (int)($ex2 - $nRadius*$lrise/$lhyp); $anResult[5] = (int)($ey2 + $nRadius*$lrun/$lhyp); $anResult[6] = (int)($ex2 + $nRadius*$lrise/$lhyp); $anResult[7] = (int)($ey2 - $nRadius*$lrun/$lhyp); } return $anResult; } /** * GetJavascriptIncludeFunctions * * javascript include files */ function GetJavascriptIncludeFunctions() { $aReturn = array(); $aReturn = parent::GetJavascriptIncludeFunctions(); /* layer_fn.js contains generic layer functions */ $szJsIncludeName = "cwc_dhtml.js"; $szInclude = ""; $aReturn[$szJsIncludeName] = $szInclude; /* maptips.js contains all the maptip js functionality */ $szJsIncludeName = $_SESSION["gszCoreWebPath"]."/widgets/MapTips/maptips.js"; $szInclude = ""; $aReturn[$szJsIncludeName] = $szInclude; /* maptips.css styles the dynamic and static DIV's used with maptips */ $szJsIncludeName = $_SESSION["gszCoreWebPath"]."/widgets/css/maptips.css"; $szInclude = ""; $aReturn[$szJsIncludeName] = $szInclude; return $aReturn; } /** * GetJavascriptInitFunctions * * @desc These get spit out at the bottom of the template after the page is processed */ function GetJavascriptInitFunctions() { $aReturn = $this->moButton->GetJavascriptInitFunctions(); $aReturn['MapTipsCreateDHTMLLayers'] = "MapTipsCreateDHTMLLayers();\n"; return $aReturn; } /** * GetHTMLHiddenVariables * * return the map size variables. */ function GetHTMLHiddenVariables() { $aReturn = $this->moButton->GetHTMLHiddenVariables(); $szVariable = "MAPTIPS_LAYER"; $szValue = "mszLayer."\">\n"; $aReturn[$szVariable] = $szValue; $szVariable = "MAPTIPS_ATTRIBUTES"; $szValue = "maszAttributes)."\">\n"; $aReturn[$szVariable] = $szValue; $szVariable = "MAPTIPS_URL"; $szValue = "mszLinkURL."\">\n"; $aReturn[$szVariable] = $szValue; $szVariable = "MAPTIPS_UNIQUEID"; $szValue = "mszLinkUniqueID."\">\n"; $aReturn[$szVariable] = $szValue; return $aReturn; } /** * GetJavascriptFunctions * * Build and return the array of functions needed in the * widget. */ function GetJavascriptFunctions() { $aReturn = $this->moButton->GetJavascriptFunctions(); if (isset($this->maSharedResourceWidgets["CWCJSAPI"])) $bCWCJSAPI = 1; else $bCWCJSAPI = 0; /* grab a handle on the map object and get the height & width */ $poMap = $this->moMapObject->oMap; $nMapWidth = $poMap->width; $nMapHeight = $poMap->height; $szJsFunctionName = "MapTipsCreateDHTMLLayers"; $szFunction = <<mszTransparentMapDiv}", -1000, -1000, {$nMapWidth}, {$nMapHeight}, true, szContent ); CWCDHTML_SetLayerZOrder( "{$this->mszTransparentMapDiv}", 500 ); szContent = 'Arrrr! This be the maptips div, ye scurvy dog!'; CWCDHTML_CreateLayer( "{$this->mszMapTipsDiv}", -1000, -1000, 200, 200, true, szContent ); CWCDHTML_SetLayerZOrder("{$this->mszMapTipsDiv}", 501 ); } EOT; $aReturn[$szJsFunctionName] = $szFunction; $szJsFunctionName = "clickMapTipsPopup"; $szButtonJS = $this->moPopup->DrawPublish(); $szFunction = <<mszHTMLForm}.MAPTIPS_LAYER.value=szLayer; {$this->mszHTMLForm}.MAPTIPS_ATTRIBUTES.value=szAttributes; {$this->mszHTMLForm}.MAPTIPS_URL.value=szURL; {$this->mszHTMLForm}.MAPTIPS_UNIQUEID.value=szUniqueID; bShow = true; if (arguments.length == 5) { bShow = arguments[4]; } if ({$bCWCJSAPI}) { //TODO: implement this! {$this->mszHTMLForm}.submit(); } else { {$this->mszHTMLForm}.submit(); } return; } EOT; $aReturn[$szJsFunctionName] = $szFunction; $szJsFunctionName = "MapTips_CaptureMouse"; $szFunction = <<< EOT function {$szJsFunctionName}() { document.onmousemove = MapTips_MouseMove; } EOT; $aReturn[$szJsFunctionName] = $szFunction; $szJsFunctionName = "MapTips_ReleaseMouse"; $szFunction = <<< EOT function {$szJsFunctionName}(e) { CWC2OnMouseMoveFunction( e ); document.onmousemove = null; } EOT; $aReturn[$szJsFunctionName] = $szFunction; $szJsFunctionName = "MapTips_MouseMove"; $szFunction = <<< EOT function {$szJsFunctionName}(e) { CWC2OnMouseMoveFunction( e ); } EOT; $aReturn[$szJsFunctionName] = $szFunction; // return the array of functions return $aReturn; } function GetJavascriptVariables() { $aReturn = array(); $aReturn['maptips_navcmd'] = 'var szMapTipsNavCmd = "";'."\n"; return $aReturn; } } ?>