Markers

Markers provide developers with the ability to superimpose DOM (html) elements directly on the chart to highlight particular time based events. Placed markers will move with the chart as a user scrolls and zooms, and they will be hidden when they pan off of the chart. Markers can be placed on the main chart panel or on study panels.

This feature requires stxAdvanced.js to function.

Example:

Click on the JavaScript, HTML and CSS buttons to see the code for this working sample. Click on the Edit in JSFiddle button to 'play' with this code.

The above working example includes a variety of different marker rendering styles using multiple HTML templates styled by CSS.

The following is an example of markers on a study panel:

Example:

Note: if markers must be part of an exported image generated using the STXSocial plug-in, you need to draw them on the actual canvas instead using Canvas Markers.

Declaring Marker Handlers

Beginning with version 2015-07, the Marker interface has been updated. It is now much simpler for developers to create markers. The new mechanism is:

new STX.Marker(params)

By default, unless a Marker placement handler and its corresponding placementFunction are declared and assigned to a marker, STXChart#defaultMarkerPlacement will be used. This is equivalent to a "placementFunction" in the previous version of Markers.

Note: prior to version 2015-09-01 you must assign an actual placement function to the default. Example:

STXChart.defaultMarkerPlacement = STX.Marker.AboveCandle.placementFunction;
Starting on version 2015-09-01 the defaultMarkerPlacement function is already pre-programmed with default placing logic. You can override this default by assigning any placement function you want to it.

You can directly use the STX.Markers class as a handler in your code or create alternate handlers. This allows you to be able to use different marker classes for different event types. So for example you can have a 'dividend' handler that places markers above the candle high, or a news handler that places the marker under the candle low or even all the way on the bottom edge of the chart. You decide.

The mechanics for creating new marker handler instance is as follows.

1 - create the function:

STX.Marker.MyHandler=function(params){
    if(!this.className) this.className="STX.Marker.MyHandler";
    STX.Marker.call(this, params);
};

2- Set the inheritance:

STX.Marker.MyHandler.stxInheritsFrom(STX.Marker, false);

3- Set the placementFunction:

STX.Marker.MyHandler.placementFunction=function(params){
    // your placement code here. See STX.Marker.AboveCandle.placementFunction and STXChart.prototype.defaultMarkerPlacement for sample code
}

Here is a basic outline for a placement function : Remember that the marker is just an HTML div, so to place it all you have to do is set its style as you would any other HTML component.

STX.Marker.MyHandler.placementFunction=function(params){
// Iterate trough the items to be placed for(var i=0;i<params.arr.length;i++){ var marker=params.arr[i]; var node=marker.node; //X axis positioning logic node.style.left=theXPixel; //Y axis positioning logic node.style.bottom=theYpixel; } };

The library provides a fully functional sample of a marker handler called [STX.Marker.AboveCandle][STX.Marker.AboveCandle, and has code showing how to implement the different parameters.

Creating an actual marker

marker = new STX.Marker.AboveCandle({
    stx: stxx,
    xPositioner: "bar",
    x: x,
    node: yourHTMLElement
});

x is the horizontal location of the marker. This is determined by the value of xPositioner which can be either:

  • "bar" - Bar position on the screen (1st candle is on the left)
  • "master" - Position in the masterData (candle will move with the chart)
  • "date" - An absolute date. This will be converted to a masterData position.
  • "none" - A raw pixel value. Positive values from left of chart. Negative values from right of chart.

For most implementations, this is all you need to position your markers. See STX.Marker for the full list of valid parameters.

Creating a div marker placeholder

At minimum, our HTML must contain the following div placeholder which will be used as a template to clone events and derive the class name for the CSS:

<div id="stxEventPrototype" class="myEvents">

You can create more placeholders if you want to have different HTML elements used for different markers. For example, you can create an element with a specific picture or specific style properties like hover or on-click. Then you would clone the appropriate template for the particular marker you want to display.

NodeCreators

For convenience, ChartIQ includes the STX.Marker.Simple factory that can create standard marker types dynamically. Circles, Squares and Callouts are supported. You can of course create your own

marker templates instead.

Here is an example on how to use the Simple factory:

function showMarkers(){
  // Remove any existing markers
  hideMarkers();
  var l=stxx.masterData.length;
  // An example of a data array to drive the marker creation
  var data=[
    {x:l-5, type:"circle", category:"news", headline:"This is a Marker for a News Item"},
    {x:l-15, type:"square", category:"earningsUp", headline:"This is a Marker for Earnings (+)"},
    {x:l-25, type:"callout", category:"earningsDown", headline:"This is a Marker for Earnings (-)"},
    {x:l-35, type:"callout", category:"dividend", headline:"This is a Marker for Dividends"},
    {x:l-45, type:"callout", category:"filing", headline:"This is a Marker for a Filing"},
    {x:l-55, type:"callout", category:"split", headline:"This is a Marker for a Split"}
  ];
  var story="Like all ChartIQ markers, the object itself is managed by the chart, so when you scroll the chart the object moves with you. It is also destroyed automatically for you when the symbol is changed.";

// Loop through the data and create markers for(var i=0;i<data.length;i++){ var datum=data[i]; datum.story=story; var params={ stx:stxx, xPositioner:"master", x: datum.x, label:"events", node: new STX.Marker.Simple(datum) }; var marker=new STX.Marker.AboveCandle(params); } stxx.draw(); }

Here is an example directly cloning the HTML template:

    newNode=$$$("#stxEventPrototype").cloneNode(true);
    newNode.id=null;
    newNode.innerHTML='F';    // future tick
    STX.appendClassName(newNode, "dividend");
    var someDate = new Date(stxx.masterData[stxx.masterData.length-1].DT);
    someDate = stxx.getNextInterval(someDate, 5); // 5 bars in the future
    new STX.Marker.AboveCandle({
        stx: stxx,
        xPositioner: "date",
        x: someDate,
        label: "events",
        node: newNode
    });

It is very important that you ensure there is a valid and complete CSS class matching the value you use in STX.appendClassName. Otherwise the marker may not be rendered if elements are missing. In the above example -STX.appendClassName(newNode, "dividend");- the "dividend" class assigns the background color for the marker. If missing, no background color will be present (since the myEvents class does not set one up) and the marker will not be visible.

Creating the markers CSS

A marker is just an HTML element that can be styled any way you want to. As such a style sheet or in-line styling is required. The following is an example of the styles provided in the advanced CSS file.

.myEvents {
    position:absolute;
    text-align:center;
    width:20px;
    height:20px;
    line-height:20px;
    color:white;
}

.myEvents.dividend{ background-color:blue; } .myEvents.news{ background-color:red; } .myEvents.earnings{ background-color:purple; }

A quick way to adjust the location of the markers to allow for the desired padding without having to create a custom placement function is to just manage it in the CSS. Remember this is a simple HTML div with a corresponding CSS. So you can just go to the style declaration and add a margin. See the highlighted padding line in this example:

.myEvents { position:absolute; text-align:center; width:20px; height:20px; line-height:20px; color:white; margin-bottom: 20px; }

Showing events on the chart. Code sample

Once all of the marker placement and styling is in place. Is time to place the markers on the chart.

var stxx=new STXChart(
    {container:$$$(".chartContainer")}
);

function showEvents(){ var markerTypes=["dividend","news","earnings"], newNode;
// markers for existing ticks for(var i=0;i<stxx.masterData.length;i+=10){ var r=Math.floor(Math.random()*(markerTypes.length+1)); if(r==markerTypes.length) continue; // randomize newNode=$$$("#stxEventPrototype").cloneNode(true); newNode.id=null; newNode.innerHTML=markerTypes[r].capitalize().charAt(0); STX.appendClassName(newNode, markerTypes[r]); new STX.Marker.AboveCandle({ stx: stxx, xPositioner: "date", x: stxx.masterData[i].DT, label: "events", node: newNode }); } // marker for a future tick newNode=$$$("#stxEventPrototype").cloneNode(true); newNode.id=null; newNode.innerHTML='F'; // future tick STX.appendClassName(newNode, "dividend"); var someDate = new Date(stxx.masterData[stxx.masterData.length-1].DT); someDate = stxx.getNextInterval(someDate, 5); // 5 bars in the future new STX.Marker.AboveCandle({ stx: stxx, xPositioner: "date", x: someDate, label: "events", node: newNode }); stxx.draw(); }

stxx.newChart("SPY", sampleData);

showEvents();

Removing Markers

Markers can remove themselves at any time:

// remove all markers
marker.remove();

Removing by label

For convenience you may also remove markers according to their specified labels:

// add a marker with a label of "events"
new STX.Marker.AboveCandle(
  {
    ....
    label: "events",
    ...
  }
);
// This removes all markers with label=="events"
STX.Marker.removeByLabel(stx, "events");

Say for example, you want to provide an interface that allows users to add and remove different types of markers individually. Assume you have News events, Dividends events and Earnings events. You can group them together so they can be removed as a group. This is managed by the 'label' within each marker.

To add them one group at a time, you would have your buttons send into the markers function some sort of label identifier that you can use to determine what group of events the user wants to see. You code should then show just these events and make sure to use the proper label. To remove those types of events you would use the STX.Marker.removeByLabel(stxx, evenType); method as stated above.

Your HTML would have something like this:

<div class="stx-btn stx-menu-btn toggle stx-collapsible" id="menuEvents" onclick="toggleEvents('news')"><span>News</span></div>
<div class="stx-btn stx-menu-btn toggle stx-collapsible" id="menuEvents" onclick="toggleEvents('earnings')"><span>Earnings</span></div>
<div class="stx-btn stx-menu-btn toggle stx-collapsible" id="menuEvents" onclick="toggleEvents('dividend')"><span>Dividends</span></div>

Your JS would have something like this:

var eventsAreDisplayed={};    // object to track th status of each marker group ( displayed or not)
// This function is called by the menu item to turn on or off the particular events
function toggleEvents(typeOfEvent){
if(eventsAreDisplayed[typeOfEvent]){ eventsAreDisplayed[typeOfEvent]=false; // turn off the flag for these events so you know they are no longer displayed STX.Marker.removeByLabel(stxx, typeOfEvent); // remove these type of events }else{ showEvents(typeOfEvent); eventsAreDisplayed[typeOfEvent]=true; } } // This function will get the requested events from the data source and displays them on the chart function showEvents(typeOfEvent){ if(!stxx.masterData) return; // your code here to get the events from your source. var myEvents = [ your list of events for this type from your back office source ]; for(var i=0;i<myEvents.length;i++){ // go trough your list of markers for this event and add them to the chart newNode=$$$("#stxEventPrototype").cloneNode(true); newNode.id=null; newNode.innerHTML='Something to show'; // usually an initial for the marker STX.appendClassName(newNode, typeOfEvent); new STX.Marker.AboveCandle({ stx: stxx, xPositioner: "date", x: myEvents[i].date, // the date you want the marker to show on label: typeOfEvent, // the type of event so you can delete them by label letter on node: newNode }); } stxx.draw(); }

Example:

Fixed Markers

Sometimes you may wish to place a marker in a fixed position on the chart. This can be accomplished with the following code:

new STX.Marker({
    node: yourNode,
    xPositioner:"none",
    yPositioner:"none"
    })

xPositioner and yPositioner when set to none will not attempt to locate the marker. It will be placed in the panel as an absolutely positioned DOM element. Use CSS to alter the position.

Some placement functions may allow you to fix the X position but set a Y position based on value:

new STX.Marker.AboveCandle({
    node: yourNode,
    xPositioner:"none"
    })

Placement of Markers

Markers by default are placed in the "subholder" for a panel. The subholder is a DIV whose borders are the edges of the panel but not including any axis. Markers placed in the subholder will "disappear" as the marker slides underneath the axis (left Y axis, right Y axis and/or x-axis)

There are two alternative locations where you can place markers by setting the following fields in your params:

  • params.includeAxis=true - If this is true then the marker will be placed in the "holder" which is a DIV that spans the entire space of a panel including the axis. Markers placed with this parameter will overlap axis as you scroll the chart.
  • params.chartContainer=true - When this is true the marker is placed in the chart container itself. Placement functions that correctly do the math will still place the marker in the desired spot, but the marker will no longer be bounded to the panel and so long as overflow is displayable on the chart container, the marker can overlap the container itself. This is useful for instance with a movable head's up display so that the edges don't get cut off as the user moves their mouse.

Managing Performance

Markers are DOM objects and it is expensive to move DOM objects around the screen. The standard ChartIQ placement functions include code to reduce the amount of DOM manipulation by checking whether a marker is off-screen. If already off-screen then positioning of the marker is skipped.

By default, markers are moved only once per 25 milliseconds. This produces a visual delay effect when panning the chart but dramatically improves chart performance. You can modify this default with the stxx.markerDelay variable (STXChart#markerDelay). Set this to zero or null to eliminate any delay, or set to the number of milliseconds that your system requires.

When thousands of markers need to be placed on the chart, and performance becomes an issue, you may opt to directly render the markers on the canvas itself.

See the following tutorial for details on how to accomplish this: Canvas Markers