Skip to main content

Betting Insights

Product Overview

Heat Map

Many points are loaded as GeoJSON to MapBoxGL.ShapeSource. A child MapBoxGL.HeatMapLayer will render these points as a heat map. The way that points combine as well as their styling is controlled by bet-maps.ts:betMapsHeatMapStyleExpression.

Polygon (Versus) Map

Many polygons are loaded via the MapBox API to a MapBoxGL.VectorSource. A separate GraphQL call returns an object that associates each feature (a single polygon) with data about the entrants. This data is used to correctly style each feature.

The user may compare up the 3 entrants at once, or in the case of sports, fixed win for either side + draw. TODO WIP

Dependencies

MapBox

MapBox provides an API, as well as native SDKs that are accessed through React Native wrapper library.

Access Tokens

Currently, we have two MapBox access Tokens for UAT and Production environments.

The UAT and Production tokens contains all public scopes.

react-native-mapbox-gl/maps

  • This library is a wrapper around the native Mapbox SDK for iOS and Android.
  • API Key must be set before rendering a Map

turf.js

  • Turf is used for geospatial calculations, like determining if the viewport is centered on the users' location.

geojson

  • Provides typings for GeoJSON standards

Component Model

In mathematics, a pure function is a function that, for a given set of inputs, always returns the same output. It also produces no side effects.

In React, a pure functional component (PFC) is a component that for a given set of props, always returns the same UI and produces no side effects.

In order to simplify testing, each UI element should be built as PFC in the component library. Inside the component library it may be wrapped with another component in order to demonstrate that it can respond correctly to props.

const PureComponent = ({ disabled, onPress, text }) => {
return (
<TouchableOpacity onPress={onPress} disabled={disabled}>
<Text>{text}</Text>
</TouchableOpacity>
);
};

const ImpureComponent = ({ disabled }) => {
const [text, setText] = useState("Hello"); // <- For a given set of props, this component may produce 2 different UIs
return (
<TouchableOpacity
onPress={() => setText("You pressed the button!")}
disabled={disabled}
>
<Text>{text}</Text>
</TouchableOpacity>
);
};

Styling

There are two sources of styling information:

Styling for the map itself (roads, suburb names, buildings, map colour) is controlled through MapBox studio. To link MapBox studio styles to React Native, pass a styleUrl prop to MapBoxGL.MapView. It will be in the format mapbox://styles/entain/xxxx.

Styling of the Heat and Polygon map is done via MapBox Style Expressions. Expressions can be created and tested in MapBox studio. Once the expression is complete, it can be exported as JSON and copied to React Native.

More complex expressions are generated by functions, whose results is passed to MapBox.

Once the styling information is passed to MapBox, everything happens in native code. This means that panning and zooming around the map should have no React Native performance overhead.

Testing

Components and functions are tested can be tested with Jest. Since react-native-mapbox-gl is rendered natively, it is not possible for Jest to grab a handle to individual map layers or elements rendered by Mapbox directly.

Implementation

Entrant ordering

  • When the map is first loaded, the first 3 entrants (by entrant number) are shown on the legend. See 'Colour Ownership' for more information on how entrants are ordered in the legend.
  • To simplify logic for sports, each 'entrant' has the following default entrant numbers. This forces the legend to always show Home, Draw, Away in that order, as their colour ownership cannot change.
    • Home = 1
    • Draw = 2
    • Away = 3

Colour Ownership

When an entrant is selected, they are assigned ownership of a colour. This means that they if they remain selected, their colour cannot change.

If the entrant is deselected, that colour is now un-owned and can be assigned freely to the next selected entrant.

When displaying entrants in the Legend and Tipping Point Sheet, runners will always be in the following order:

  • Red
  • Green
  • Blue

The entrant number has no bearing on how entrants are ordered. It is driven completely by colour ownership.

File Structure

  • Components: app/components/betting-insights/bet-maps/
  • Jest Tests: app/components/betting-insights/bet-maps/__tests__/
  • Utils: app/utils/bet-maps.ts