Skip to content

Commit

Permalink
Merge bbc4c90 into 336783e
Browse files Browse the repository at this point in the history
  • Loading branch information
ajduberstein committed Sep 9, 2019
2 parents 336783e + bbc4c90 commit f74eacc
Show file tree
Hide file tree
Showing 6 changed files with 224 additions and 2 deletions.
29 changes: 28 additions & 1 deletion docs/api-reference/deck.md
Expand Up @@ -138,7 +138,7 @@ Canvas ID to allow style customization in CSS.

##### `style` (Object, optional)

Css styles for the deckgl-canvas.
CSS styles for the deckgl-canvas.

##### `touchAction` (String, optional)

Expand All @@ -152,6 +152,33 @@ By default, the deck canvas captures all touch interactions. This prop is useful

Extra pixels around the pointer to include while picking. This is helpful when rendered objects are difficult to target, for example irregularly shaped icons, small moving circles or interaction by touch. Default `0`.

#### `getTooltip` (Function, optional)

Callback that takes a hovered-over point and renders a tooltip. If the prop is not specified, the tooltip is hidden.

Callback arguments:

* `info` - the [picking info](/docs/developer-guide/interactivity.md#the-picking-info-object) describing the object being hovered.

If the callback returns `null`, the tooltip is hidden, with the CSS `display` property set to `none`.
If the callback returns a string, that string is rendered in a tooltip with the default CSS styling described below.
Otherwise, the callback can return an object with the following fields:

* `text` (String, optional) - Specifies the `innerText` attribute of the tooltip.
* `html` (String, optional) - Specifies the `innerHTML` attribute of the tooltip. Note that this will override the specified `innerText`.
* `className` (String, optional) - Class name to attach to the tooltip element. The element has the default class name of `deck-tooltip`.
* `style` (Object, optional) - An object of CSS styles to apply to the tooltip element, which can override the default styling.

By default, the tooltip has the following CSS style:

```css
z-index: 1;
position: absolute;
color: #a0a7b4;
background-color: #29323c;
padding: 10px;
```

##### `useDevicePixels` (Boolean, optional)

When true, device's full resolution will be used for rendering, this value can change per frame, like when moving windows between screens or when changing zoom level of the browser.
Expand Down
2 changes: 2 additions & 0 deletions examples/experimental/json-examples/3d-heatmap.json
Expand Up @@ -21,6 +21,8 @@
"id": "heatmap",
"data": "https://raw.githubusercontent.com/uber-common/deck.gl-data/master/examples/3d-heatmap/heatmap-data.csv",
"coverage": 1,
"pickable": true,
"autoHighlight": true,
"elevationRange": [0, 3000],
"elevationScale": 50,
"extruded": true,
Expand Down
15 changes: 14 additions & 1 deletion modules/core/src/lib/deck.js
Expand Up @@ -25,6 +25,7 @@ import EffectManager from './effect-manager';
import Effect from './effect';
import DeckRenderer from './deck-renderer';
import DeckPicker from './deck-picker';
import Tooltip from './tooltip';
import log from '../utils/log';
import deckGlobal from './init';

Expand Down Expand Up @@ -222,6 +223,11 @@ export default class Deck {
this.eventManager.destroy();
}

if (this.tooltip) {
this.tooltip.remove();
this.tooltip = null;
}

if (!this.props.canvas && !this.props.gl && this.canvas) {
// remove internally created canvas
this.canvas.parentElement.removeChild(this.canvas);
Expand Down Expand Up @@ -559,8 +565,13 @@ export default class Deck {
_pickRequest
)
);
const shouldGenerateInfo = _pickRequest.callback || this.props.getTooltip;
const pickedInfo = shouldGenerateInfo && (result.find(info => info.index >= 0) || emptyInfo);
if (this.props.getTooltip) {
const displayInfo = this.props.getTooltip(pickedInfo);
this.tooltip.setTooltip(displayInfo, pickedInfo.x, pickedInfo.y);
}
if (_pickRequest.callback) {
const pickedInfo = result.find(info => info.index >= 0) || emptyInfo;
_pickRequest.callback(pickedInfo, _pickRequest.event);
}
_pickRequest.mode = null;
Expand All @@ -584,6 +595,8 @@ export default class Deck {
trackContextState(gl, {enable: true, copyState: true});
}

this.tooltip = new Tooltip(this.canvas);

setParameters(gl, {
blend: true,
blendFunc: [GL.SRC_ALPHA, GL.ONE_MINUS_SRC_ALPHA, GL.ONE, GL.ONE_MINUS_SRC_ALPHA],
Expand Down
75 changes: 75 additions & 0 deletions modules/core/src/lib/tooltip.js
@@ -0,0 +1,75 @@
// Copyright (c) 2015 - 2019 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

/* global document */
const defaultStyle = {
zIndex: 1,
position: 'absolute',
pointerEvents: 'none',
color: '#a0a7b4',
backgroundColor: '#29323c',
padding: '10px',
top: 0,
left: 0,
display: 'none'
};

export default class Tooltip {
constructor(canvas) {
const canvasParent = canvas.parentElement;

if (canvasParent) {
this.el = document.createElement('div');
this.el.className = 'deck-tooltip';
Object.assign(this.el.style, defaultStyle);
canvasParent.appendChild(this.el);
}
}

setTooltip(displayInfo, x, y) {
const el = this.el;

if (typeof displayInfo === 'string') {
el.innerText = displayInfo;
} else if (!displayInfo) {
el.style.display = 'none';
return;
} else {
if ('text' in displayInfo) {
el.innerText = displayInfo.text;
}
if ('html' in displayInfo) {
el.innerHTML = displayInfo.html;
}
if ('className' in displayInfo) {
el.className = displayInfo.className;
}
Object.assign(el.style, displayInfo.style);
}
el.style.display = 'block';
el.style.transform = `translate(${x}px, ${y}px)`;
}

remove() {
if (this.el) {
this.el.remove();
}
}
}
1 change: 1 addition & 0 deletions test/modules/core/lib/index.js
Expand Up @@ -29,6 +29,7 @@ import './layer.spec';
import './composite-layer.spec';
import './layer-extension.spec';
import './layer-manager.spec';
import './tooltip.spec';
import './transition-manager.spec';
import './uniform-transition-manager.spec';
import './seer-integration.spec';
Expand Down
104 changes: 104 additions & 0 deletions test/modules/core/lib/tooltip.spec.js
@@ -0,0 +1,104 @@
/* global window */
import Tooltip from '@deck.gl/core/lib/tooltip';
import test from 'tape-catch';

let document;
if (typeof window === undefined || !window.document) {
const {JSDOM} = require('jsdom');
const dom = new JSDOM(`<!DOCTYPE html>`);
document = dom.window.document;
} else {
document = window.document;
}

const CANVAS_PARENT_CLASS_NAME = 'tooltip-canvas-parent';
const pickedInfo = {object: {elevationValue: 10}, x: 0, y: 0};

function setup() {
const canvas = document.createElement('canvas');
const canvasParent = document.createElement('div');
canvasParent.className = 'tooltip-canvas-parent';
canvasParent.appendChild(canvas);
document.body.appendChild(canvasParent);
return new Tooltip(canvas);
}

function teardown() {
const el = document.getElementsByClassName(CANVAS_PARENT_CLASS_NAME)[0];
el.remove();
}

function getTooltipFunc(pickedValue) {
return {
className: 'coolTooltip',
html: `<strong>Number of points:</strong> ${pickedValue.object.elevationValue}`,
style: {
backgroundColor: 'lemonchiffon'
}
};
}

function getTooltipFuncDefault(pickedValue) {
return {
text: `Number of points: ${pickedValue.object.elevationValue}`
};
}

test('Tooltip#constructor', t => {
const tooltip = setup(); // eslint-disable-line
t.ok(document.getElementsByClassName('deck-tooltip'), 'Tooltip exists in document');
t.equals(document.getElementsByClassName('deck-tooltip')[0].style.top, '0px');
teardown();
t.end();
});

test('Tooltip#setTooltip', t => {
const tooltip = setup();
tooltip.setTooltip(getTooltipFunc(pickedInfo), pickedInfo.x, pickedInfo.y);
t.equals(tooltip.el.style.backgroundColor, 'lemonchiffon');
t.equals(tooltip.el.innerHTML, '<strong>Number of points:</strong> 10');
t.equals(tooltip.el.className, 'coolTooltip');
teardown();
t.end();
});

test('Tooltip#setTooltipWithString', t => {
const tooltip = setup();
const pickedInfoFunc = info => `Number of points: ${info.object.elevationValue}`;
tooltip.setTooltip(pickedInfoFunc(pickedInfo), pickedInfo.x, pickedInfo.y);
t.equals(tooltip.el.innerText, 'Number of points: 10');
t.equals(tooltip.el.className, 'deck-tooltip');
teardown();
t.end();
});

test('Tooltip#setTooltipDefaults', t => {
const tooltip = setup();
const tooltipResult = getTooltipFuncDefault(pickedInfo);
tooltip.setTooltip(tooltipResult, pickedInfo.x, pickedInfo.y);
t.equals(tooltip.el.innerText, 'Number of points: 10');
t.equals(tooltip.el.className, 'deck-tooltip');
teardown();
t.end();
});

test('Tooltip#setTooltipNullCase', t => {
const tooltip = setup();
tooltip.setTooltip(null, pickedInfo.x, pickedInfo.y);
t.equals(tooltip.el.style.display, 'none');
teardown();
t.end();
});

test('Tooltip#remove', t => {
const tooltip = setup();
t.equals(document.getElementsByClassName('deck-tooltip').length, 1, 'Tooltip element present');
tooltip.remove();
t.equals(
document.getElementsByClassName('deck-tooltip').length,
0,
'Tooltip element successfully removed'
);
teardown();
t.end();
});

0 comments on commit f74eacc

Please sign in to comment.