# Making Controls for a Map
CGView.js does not provide any interface controls for interacting with a map
(with the exception of the color picker when a legend swatch is clicked).
Adding controls is easy, as this tutorial will show. And the code used here to
generate controls can be used as a starting point in other projects.
All the [examples](../examples/index.html) use the same controls created here.
## Adding HTML for Controls
Below the 'my-viewer' div, we will add a number of buttons which will be hooked up to perform actions on the map.
Here is the HTML
```html
```
Here is what the controls will look like:
For simplicity, the SVG images are embedded in the CSS. The CSS for the example
controls is available here: [controls.css](../styles/controls.css)
The complete JavaScript for the controls (described below) can be downloaded
here: [controls.js](../scripts/controls.js)
## Create [Viewer](../api/Viewer.html)
Create the viewer so we can interact with it.
```js
// Create the viewer
cgv = new CGV.Viewer('#my-viewer', {
height: 500,
width: 500,
});
// Load an exmaple JSON file
var request = new XMLHttpRequest();
request.open('GET', '../data/json/NZ_CP010546.json', true);
request.onload = function() {
var response = request.response;
const json = JSON.parse(response);
cgv.io.loadJSON(json);
cgv.draw()
};
request.send();
```
## Adding JavaScript for Controls
First let's make a helper method to simplify adding click handlers to the buttons.
```js
// Helper to add click handlers to buttons
onClick = function(id, func) {
const btn = document.getElementById(id);
btn.addEventListener('click', func);
}
```
###
Reset Button
The [reset()](../api/Viewer.html#reset) method centers the map and set the zoom level to 1.
```js
// Reset Map Button
onClick('btn-reset', () => {
cgv.reset();
});
```
###
Zoom In/Out
The [zoomIn()](../api/Viewer.html#zoomIn) and
[zoomOut()](../api/Viewer.html#zoomOut) methods zoom the map in or out by a
factor. The default factor is 2.
```js
// Zoom In Button
onClick('btn-zoom-in', () => {
cgv.zoomIn()
});
// Zoom Out Button
onClick('btn-zoom-out', () => {
cgv.zoomOut()
});
```
###
Move Left/Right
The [moveLeft()](../api/Viewer.html#moveLeft) and
[moveRight()](../api/Viewer.html#moveRight) methods move the map
left/counterclockwise or right/clockwise by a factor of the visible map (the
default is 0.5). This allows moving the same visible amount independent of the
zoom level. For example, if 1000 bp are currently visible then the default move
would be 500 bp. Moving to a specific region can be performed with the
[moveTo()](../api/Viewer.html#moveTo) method.
```js
// Move Left/Counter-Clockwise
onClick('btn-move-left', () => {
cgv.moveLeft();
});
// Move Right/Clockwise
onClick('btn-move-right', () => {
cgv.moveRight();
});
```
###
Change Map Format
The map format (circular or linear) is changed via settings
[update()](../api/Settings.html#update).
```js
// Change Map Format Linear <-> Circular
onClick('btn-toggle-format', () => {
const format = (cgv.format == 'circular') ? 'linear' : 'circular';
cgv.settings.update({ format: format });
cgv.draw();
});
```
###
Invert Map Colors
All the colors on the map (e.g. features, background, captions) can be changed
with a single viewer command:
[invertColors()](../api/Viewer.html#invertColors).
```js
// Invert the Map Colors
onClick('btn-invert-colors', () => {
cgv.invertColors();
});
```
###
Move to a Random Feature
This button show how easy it is to move to a feature using the feature
[moveTo()](../api/Feature.html#moveTo).
```js
// Move to Random Feature
onClick('btn-random-feature', () => {
// Choose a random feature
const number = Math.ceil(Math.random() * cgv.features().length);
const feature = cgv.features(number);
// Take 1.5 seconds to move to the feature (the default is 1 second)
feature.moveTo(1500);
});
```
###
Download PNG Button
Download the currently visible map using the IO
[downloadImage()](../api/IO.html#downloadImage) method.
Images up to 8000 x 8000 px can be downloaded.
```js
// Download PNG
onClick('btn-download', () => {
const height = 2000;
// Here we adjust the width to be proportional to the height
const width = cgv.width / cgv.height * height;
cgv.io.downloadImage(width, height, 'cgview_map.png');
});
```
###
Toggle Feature Labels
This button toggles the visibility of the labels using annotation [update()](../api/annotation.html#update).
```js
// Toggle Labels
onClick('btn-toggle-labels', () => {
cgv.annotation.update({visible: !cgv.annotation.visible});
cgv.draw();
});
```
##
Start/Stop Animation
This button starts or stops an animation cycling through 5 random features using [animate()](../api/viewer.html#animate).
```js
// Start/Stop Animation
onClick('btn-animate', () => {
cgv.isAnimating ? cgv.stopAnimate() : cgv.animate();
});
```
## Draw the Map ##
```js
cgv.draw();
```
The resulting Viewer (id='my-viewer') with custom controls is below.