Skip to main content

Backgrounds

The surface widget supports the addition of backgrounds via a plugin. Two different background types are supported - images, and generated grids.

Setup​

As this is a plugin, you will provide its configuration in the plugins section of the render parameters for a surface.

<script setup>

import { BackgroundPlugin, SimpleBackground } from "@visuallyjs/browser-ui"

const renderOptions = {
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: SimpleBackground.type,
url: "/img/351032562.jpg"
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

Image backgrounds​

Images can be used as a background in one of two ways - either as an image that is retrieved in one piece and displayed, or as a set of tiles.

Simple backgrounds​

These are backgrounds consisting of a single image, positioned at the Surface's origin. This type of background can be useful, for example, if you're building an app in which your users can markup drawings.

Single image example​

In this example (using the code shown above) we load a simple background, ie. a static image:

Remember that we paste the image at the canvas origin, at its original size. So in this case the image has loaded but we cannot see all of it. It is possible to get a notification when the background image has loaded, though, so we can hook into that and have the image fully visible after load:

<script setup>

import { BackgroundPlugin, SimpleBackground } from "@visuallyjs/browser-ui"

const renderOptions = {
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: SimpleBackground.type,
url: "/img/351032562.jpg",
onBackgroundReady: (bg, surface) => {
surface.zoomToBackground()
}
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

Tiled backgrounds​

This type of background consists of a set of tiles, which the Surface element requests from you as the canvas is panned and zoomed. This type of background has various usages: if you have a large background image, for instance, you may wish to serve it in pieces as the Surface needs it. Alternatively, you may wish to change the background based on the current zoom (in the way that Google maps does). Another great use for this type of background is to provide a grid for your canvas.

Tiled image example​

In this example we use a tiled background. Each of our tiles looks like this:

VisuallyJs - build diagrams and rich visual UIs fast

When the surface has rendered, only the required tiles will have been loaded. If you tap on one of the nodes, the display will pan left and up by 350 pixels in each axis, and you will (probably) see new tiles appearing as they get loaded (unless the network is too fast for the load to be evident):

<script setup>

import { BackgroundPlugin, TiledBackground, TilingStrategies } from "@visuallyjs/browser-ui"

const renderOptions = {
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: TiledBackground.type,
tiling: TilingStrategies.absolute,
url: "/img/tiles/{z}/{x}_{y}.jpg",
tileSize: {
width: 200,
height: 200
},
width: 800,
height: 800,
maxZoom: 0
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

Tiling strategies​

You may have noticed that in the example above we declared tiling:TilingStrategies.absolute in the background options. The tiled background supports two different approaches to the way tiles are arranged:

  • TilingStrategies.absolute - Divides the entire image dimensions by the tile size. For instance, if you declare your background has a width and height of 800px, and your tiles are of width and height 50px, then - at zoom 0 - the background expects 16 tiles in each axis. At zoom 1, the expected value is doubled to 32, at zoom 2 it doubles again to 64, etc. With this strategy, each zoom level has the same number of tiles.

  • TilingStrategies.logarithmic - With this strategy, there are (2^level+1) tiles in each axis. For instance at zoom 0, there are 2 tiles. At zoom 1 there are 4. At zoom 2, there are 8. Etc. This strategy is how applications like Google maps operate.

A tiled background is served as a series of layers, one for each zoom level supported. The number of zoom levels you intend to support is specified by the maxZoom option, which is a zero-indexed integer value. A value of 0 is the base value, covering the entire background. The background will determine which zoom level is appropriate based upon the current zoom of the surface.

There is no need to support any zoom level beyond 0; the background will retrieve tiles for the most appropriate level that is available to it, but serving up different tiles at different levels can allow you to implement things like serving more visual complexity the further a user zooms in.

URL pattern​

The URL you supply for a tiled background should have a placeholder for each of z (zoom), x (index in horizontal axis) and y (index in vertical axis), as in the example above. In the above example we provided this url pattern:

{
url:"/img/tiles/{z}/{x}_{y}.jpg",
}

Tiles are zero-indexed, so, for example, the top left tile at zoom level 0 would, in the previous example, expand to this url:

tiles/0/tile_0_0.png

The surface's tiled background does not support the concept of a "continuous world", in which tiles with negative indices may be requested.

Clamping to the background image​

Depending on your use case, you may wish to force the surface to clamp the pan/zoom such that some portion of the background image is always visible. You do this by setting the clampToBackground parameter on a render call:

<script setup>

import { BackgroundPlugin, SimpleBackground } from "@visuallyjs/browser-ui"

const renderOptions = {
clampToBackground: true,
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: SimpleBackground.type,
url: "myBackground.png"
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

Zooming to the background image​

If you wish to zoom out to the point that the entire background image is visible:

surface.zoomToBackground()

Generated grid backgrounds​

Generated grid backgrounds place an SVG element into the background of the UI, repositioning and resizing it as needed as the bounds of your content changes. You can choose between a background using lines or dots. The default is for lines.

<script setup>

import { BackgroundPlugin, GeneratedGridBackground } from "@visuallyjs/browser-ui"

const renderOptions = {
grid: {
size: {
width: 50,
height: 50
}
},
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: GeneratedGridBackground.type
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

In this example we didn't specify the size of the grid in the background's options: the background will get this information from the surface, if possible. You can override the surface grid, however, should you wish to, or you may use the grid background on a surface that does not have a drag grid in effect.

Dotted backgrounds​

The background in this example is rendered as lines, which is the default. Here's the same example with gridType:GridTypes.dotted:

The full list of options for the generated grid background are:

GeneratedGridBackgroundOptions
Options for the generated grid background.
NameTypeDescription
autoShrink?booleanDefaults to true, and instructs the grid that if the grid has grown beyond any minimum value set in either axis, if the content bounds subsequently shrink in that axis below the minimum, the grid should shrink back to the minimum. If you set this to false the grid will never shrink back to its minimum values once they have been exceeded.
dotRadius?numberThe radius for dots representing grid positions (when gridType id GridTypes.dotted). Defaults to 2.
grid?GridThe grid to use. This is optional; if you do not supply one the background will attempt to read the grid definition from the Surface. If that is also not set then a default grid of 50x50 pixels will be used.
gridType?GridTypeType of grid - lines or dots. Defaults to lines.
maxHeight?numberThe maximum height for the grid. The value you provided is divided by 2 and then the grid is guaranteed to never exceed the range of (-maxHeight / 2) - (maxHeight / 2). maxHeight takes precedence over minHeight.
maxWidth?numberThe maximum width for the grid. The value you provided is divided by 2 and then the grid is guaranteed to never exceed the range of (-maxWidth / 2) - (maxWidth / 2). maxWidth takes precedence over minWidth.
minHeight?numberThe minimum height for the grid. The value you provided is divided by 2 and then the grid is guaranteed to always at least span the range of (-minHeight / 2) - (minHeight / 2). Defaults to 20 000.
minWidth?numberThe minimum width for the grid. The value you provided is divided by 2 and then the grid is guaranteed to always at least span the range of (-minWidth / 2) - (minWidth / 2). Defaults to 20 000.
onBackgroundReady?OnBackgroundReadyCallbackOptional function to call when the image has loaded (or otherwise claims to be ready)
showBorder?booleanWhether or not to show a thick border around the entire background. Defaults to false.
showTickMarks?booleanDefaults to false. If true, the grid will also draw tick marks between the grid lines.
tickDotRadius?numberThe radius for dots representing grid tick marks (when gridType id GridTypes.dotted). Defaults to 1.
tickMarksPerCell?numberNumber of tick marks to draw per cell. Defaults to 2.
typestringType of background to render.
visible?booleanWhether or not the background is initially visible. Defaults to true.

Autoscaling​

The grid background has a minimum width and height, which are set by default to quite large numbers, and so users typically do not see the edges of the grid. However, you can supply your own minWidth and/or minHeight values, and if these are quite small with respect to the bounds of the dataset, VisuallyJs will autoscale the grid as necessary.

In this example we've set our grid minimum width and height to be 500 pixels. If you drag one of the nodes in the canvas below towards the edge of the grid, you'll see the grid expand in order to ensure there are always at least 2 grid squares between the content bounds and the edge of the grid. The grid will also shrink subsequently back to any minimum boundaries if the content bounds shrinks appropriately.

<script setup>

import { BackgroundPlugin, GeneratedGridBackground } from "@visuallyjs/browser-ui"

const renderOptions = {
grid: {
size: {
width: 50,
height: 50
}
},
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: GeneratedGridBackground.type,
minWidth: 500,
minHeight: 500,
autoShrink: false
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

Autoshrink​

In the above example the grid scales up and down as the bounds of the content changes. If you wish, you can switch off the autoShrink functionality:

<script setup>

import { BackgroundPlugin, GeneratedGridBackground } from "@visuallyjs/browser-ui"

const renderOptions = {
grid: {
size: {
width: 50,
height: 50
}
},
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: GeneratedGridBackground.type,
minWidth: 1500,
minHeight: 1500,
autoShrink: false
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

Tick marks​

By default, the grid will be drawn without tick marks in each cell. You can change this behaviour with the showTickMarks and tickMarksPerCell options. In this first example we show the tick marks:

<script setup>

import { BackgroundPlugin, GeneratedGridBackground } from "@visuallyjs/browser-ui"

const renderOptions = {
grid: {
size: {
width: 50,
height: 50
}
},
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: GeneratedGridBackground.type,
showTickMarks: true
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

In this next example, we leave the drag grid at 50x50 on the Surface, but we expand the background grid to 250x250, and request 4 tick marks per cell:

<script setup>

import { BackgroundPlugin, GeneratedGridBackground } from "@visuallyjs/browser-ui"

const renderOptions = {
grid: {
size: {
width: 50,
height: 50
}
},
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: GeneratedGridBackground.type,
showTickMarks: true,
tickMarksPerCell: 5,
grid: {
width: 250,
height: 250
}
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

Grid border​

You can add a border to the background grid with the showBorder option:

<script setup>

import { BackgroundPlugin, GeneratedGridBackground } from "@visuallyjs/browser-ui"

const renderOptions = {
grid: {
size: {
width: 50,
height: 50
}
},
plugins: [
{
type: BackgroundPlugin.type,
options: {
type: GeneratedGridBackground.type,
minWidth: 1500,
minHeight: 1500,
showBorder: true
}
}
]
}


</script>
<template>
<SurfaceComponent :renderOptions="renderOptions" />
</template>

CSS classes​

VisuallyJs exposes a number of CSS classes to assist you in managing the appearance of grid backgrounds.

ClassDescription
vjs-backgroundThe css class that will be added to a grid background's main element
vjs-background-borderThe css class that will be added to a grid background's border
vjs-background-gridThe css class that will be added to the major and minor dots/lines in a grid background
vjs-background-grid-dotted-majorThe class that will be added to the dots representing a grid background's grid lines (when gridType is GridTypes.dotted)
vjs-background-grid-dotted-minorThe class that will be added to the dots representing a grid background's grid tick marks (when gridType is GridTypes.dotted)
vjs-background-grid-majorThe class that will be added to the lines representing a grid background's grid lines (when gridType is GridTypes.lines)
vjs-background-grid-minorThe class that will be added to the lines representing a grid background's tick marks (when gridType is GridTypes.lines)