Text
Take a look at this text and you'll see that text is actually very complicated to create. In 3D renderings, text requires a lot of polygons to look 3D and look good.
There are a number of different ways to add text to 3D scenes.
Loading Fonts
To render text, we need to have some fonts. The easiest approach to get started is to use the fonts that are defined in the CMFont.js file and then call CMText to load the fonts. You'll need to add an entry to load the CMFint.js file in your header as follows:
<script src="https://gsp.humboldt.edu/Archive/fonts/2019/CMFonts.js" /script> <!-- file with the URLs for the standard fonts --->
The fonts have to be loaded from the server to the client and this is best done before we create any additional maps so we know the fonts are available. One approach is to create a new OnLoad() function that loads the fonts and provides a callback function to the old OnLoad() function to create our maps. First, rename your "OnLoad()" function to something like "LoadMap()" and create a new OnLoad() function that calls CM3Text to load the fonts and provide a callback to your LoadMap() function.
function OnLoad() { // before using text, we need to load the fonts and then we can initialize the map CM3Text.LoadFonts(CMFonts,LoadMap); } function LoadMap() { // old OnLoad() code }
3D Text
You can create 3D extruded text for your renderings just like you've seen in the movies. Remember that this is expensive.
In CanvasMap, text can be added using a special layer for general 3D items. The code below will add the text "Antarica" to a geographic map with a very small bevel to make it look good. The extrusion settings are the same as for CM3LayerVector. The Font settings are different from 2D fonts and may change in the future. For now:
- size: the size of the text in reference units
- GlobalFontIndex: the file CMFonts.js contains an array of fonts which we loaded in the code above. The GlobalFontIndex is an index into this array to select the font for the text.
Remember that you'll need to change the "SetSetting("PositionOffset",[X,Y,Z])" values based on the spatial reference and units you are using. You can also change the size of the text and change the font size. By default, text is drawn on the x-y plane. You can change this by rotating the text about the x-axis.
// add the layer for the text items var TheLayerItems=new CM3LayerItems(); TheLayerItems.SetSetting("Name","3D Items"); TheMainContainer.AddLayer(TheLayerItems); // add the text item var TheText=new CM3Text("Antartica");
TheText.SetSetting("Style","fillStyle","rgba(200,200,200,1)");
TheText.SetSetting("Extrusion","bevelSize",.1);
TheText.SetSetting("Extrusion","bevelThickness",.1);
TheText.SetSetting("Font","size","12");
TheText.SetSetting("Font","GlobalFontIndex",2);
TheText.SetSetting("Item","Rotation",[Math.PI/2,0,0]);
TheText.SetSetting("Item","PositionOffset",[60,-80,10]);
TheLayerItems.AddChild(TheText);
Sprite Text
Another approach is to use a Canvas element to place a "sprite" in the 3D scene. Sprites are special 3D objects that always render toward the view and can be used to put labels that hover over spatial data.
The samle below will add the text "USA" over the US. Note that since sprite text is a Canvas,you can use the same settings for the CM3SpriteText object as you would for other 2D objects.
var TheLayerItems=new CM3LayerItems(); TheLayerItems.SetSetting("Name","3D Items"); var TheBox=new CM3SpriteText("USA"); TheBox.SetSetting("Style","fillStyle","rgba(0,200,255,1)"); TheBox.SetSetting("Text","font","40px Arial"); TheBox.SetSetting("Position","Translations",[-90,40,10]); TheLayerItems.AddChild(TheBox); TheMainContainer.AddLayer(TheLayerItems);
The code sample below shows a full example of pulling text from a vector layer's attributes and displaying it in sprite text objects in a scene with projected data.
var TheLayerItems=new CM3LayerItems(); // create the layer for the items TheLayerItems.SetSetting("Name","3D Items"); // set the name so we can see it in the layer list TheMainContainer.AddLayer(TheLayerItems); // add the layer to the scene // save the item layer into the point layer so we can access it after the point layer loads TheLayer.TheLayerItems=TheLayerItems; // save the OnLoad function call before we replace it TheLayer.CMLayerVector3D_OnLoad=TheLayer.OnLoad; // replace the onload call with our own to add the labels TheLayer.OnLoad=function() { // call the old onload function this.CMLayerVector3D_OnLoad(); var TheDataset=this.GetDataset(); // get the dataset that contains the data var CallSignIndex=TheDataset.GetAttributeIndexFromHeading("CALL_SIGN"); var NumFeatures=TheDataset.GetNumFeatures(); var TheRegions=TheDataset.GetRegions(); // get the spatial data for the features var TheLayerItems=this.TheLayerItems; // get back our layer for the labels for (var i=0;i<NumFeatures;i++) { var TheRegion=TheRegions[i]; // get the region (features spatial data) var X=TheRegion[0]; // get the x and y values var Y=TheRegion[1]; var Z=15000; // set the Z value to be above the surface // get the attribute to put into the text box var TheCallSign=TheDataset.GetAttributeCell(CallSignIndex,i); // create the object for the text var TheBox=new CM3SpriteText(TheCallSign); // set the settings for drawing the text and box TheBox.SetSetting("Style","fillStyle","rgba(0,200,255,1)"); TheBox.SetSetting("Text","font","20px Arial"); TheBox.SetSetting("Position","Translations",[X,Y,Z]); // set the position of the center of the box TheBox.SetSetting("Position","Scales",[20000,20000,1]); // ake the box larger for projected data TheLayerItems.AddChild(TheBox); // add the box to the layer } }