提交 dc1e1c1a 编写于 作者: K Kamran Ahmed

WIP - Remove canvas and use HTML/CSS

上级 e19deb41
......@@ -320,6 +320,9 @@ activeElement.getNode(); // Gets the DOM Element behind this element
</div>
</div>
<div id="driver-page-overlay"></div>
<div id="driver-highlighted-element-stage"></div>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
<script async defer src="//buttons.github.io/buttons.js"></script>
<script src="//twemoji.maxcdn.com/2/twemoji.min.js?2.5"></script>
......
......@@ -138,6 +138,9 @@ export default class Element {
*/
onDeselected() {
this.hidePopover();
this.node.classList.remove('driver-highlighted-element');
this.highlightFinished = false;
if (this.options.onDeselected) {
......@@ -145,6 +148,14 @@ export default class Element {
}
}
getSize() {
const boundingRect = this.node.getBoundingClientRect();
return {
width: boundingRect.width,
height: boundingRect.height
};
}
/**
* Is called when the element is about to be highlighted
* i.e. either if overlay has started moving the highlight towards
......@@ -168,6 +179,8 @@ export default class Element {
onHighlighted() {
this.showPopover();
this.node.classList.add('driver-highlighted-element');
this.highlightFinished = true;
const highlightedElement = this;
......
import Position from './position';
import { ID_OVERLAY, OVERLAY_ZINDEX } from '../common/constants';
/**
* Responsible for overlay creation and manipulation i.e.
......@@ -14,10 +13,8 @@ export default class Overlay {
constructor(options, window, document) {
this.options = options;
this.overlayAlpha = 0; // Is used to animate the layover
this.positionToHighlight = new Position({}); // position at which layover is to be patched at
this.highlightedPosition = new Position({}); // position at which layover is patched currently
this.redrawAnimation = null; // used to cancel the redraw animation
this.highlightedElement = null; // currently highlighted dom element (instance of Element)
this.lastHighlightedElement = null; // element that was highlighted before current one
......@@ -27,31 +24,16 @@ export default class Overlay {
this.document = document;
this.resetOverlay();
this.setSize();
}
/**
* Prepares the overlay
*/
resetOverlay() {
// Check and remove the canvas if it already exists
const canvasOverlay = this.document.getElementById(ID_OVERLAY);
if (canvasOverlay && canvasOverlay.parentNode) {
canvasOverlay.parentNode.removeChild(canvasOverlay);
}
const overlay = this.document.createElement('canvas');
// @todo: append the elements if not there already
this.overlay = overlay;
this.context = overlay.getContext('2d');
this.overlay.id = ID_OVERLAY;
this.overlay.style.pointerEvents = 'none';
this.overlay.style.background = 'transparent';
this.overlay.style.position = 'fixed';
this.overlay.style.top = '0';
this.overlay.style.left = '0';
this.overlay.style.zIndex = OVERLAY_ZINDEX;
this.pageOverlay = this.document.getElementById('driver-page-overlay');
this.highlightStage = this.document.getElementById('driver-highlighted-element-stage');
}
/**
......@@ -65,9 +47,6 @@ export default class Overlay {
return;
}
// @todo put it in the caller after testing
this.setSize();
// Trigger the hook for highlight started
element.onHighlightStarted();
......@@ -123,6 +102,9 @@ export default class Overlay {
this.highlightedElement = null;
this.lastHighlightedElement = null;
this.pageOverlay.style.display = 'none';
this.highlightStage.style.display = 'none';
this.draw();
}
......@@ -132,135 +114,26 @@ export default class Overlay {
* Slowly eases towards the item to be selected.
*/
draw() {
// Cache the response of this for re-use below
const canHighlight = this.positionToHighlight.canHighlight();
// Remove the existing cloak from the body
// it might be torn i.e. have patches from last highlight
this.removeCloak();
// Add the overlay on top of the whole body
this.addCloak();
const isFadingIn = this.overlayAlpha < 0.1;
if (canHighlight) {
if (isFadingIn) {
// Ignore the animation, just highlight the item at its current position
this.highlightedPosition = this.positionToHighlight;
} else {
// Slowly move towards the position to highlight
this.highlightedPosition.left += (this.positionToHighlight.left - this.highlightedPosition.left) * 0.18;
this.highlightedPosition.top += (this.positionToHighlight.top - this.highlightedPosition.top) * 0.18;
this.highlightedPosition.right += (this.positionToHighlight.right - this.highlightedPosition.right) * 0.18;
this.highlightedPosition.bottom += (this.positionToHighlight.bottom - this.highlightedPosition.bottom) * 0.18;
}
}
// Cut the chunk of overlay that is over the highlighted item
this.removeCloak({
posX: this.highlightedPosition.left - this.window.scrollX - this.options.padding,
posY: this.highlightedPosition.top - this.window.scrollY - this.options.padding,
width: (this.highlightedPosition.right - this.highlightedPosition.left) + (this.options.padding * 2),
height: (this.highlightedPosition.bottom - this.highlightedPosition.top) + (this.options.padding * 2),
});
// Fade the overlay in if we can highlight
if (canHighlight) {
if (!this.options.animate) {
this.overlayAlpha = this.options.opacity;
} else {
this.overlayAlpha += (this.options.opacity - this.overlayAlpha) * 0.08;
}
} else {
// otherwise fade out
this.overlayAlpha = Math.max((this.overlayAlpha * 0.85) - 0.02, 0);
}
// cancel any existing animation frames
// to avoid the overlapping of frames
this.window.cancelAnimationFrame(this.redrawAnimation);
// Continue drawing while we can highlight or we are still fading out
if (canHighlight || this.overlayAlpha > 0) {
// Add the overlay if not already there
if (!this.overlay.parentNode) {
this.document.body.appendChild(this.overlay);
}
// Stage a new animation frame only if the position has not been reached
// or the alpha has not yet fully reached fully required opacity
if (!this.hasPositionHighlighted()) {
this.redrawAnimation = this.window.requestAnimationFrame(this.draw);
} else if (!this.options.animate && isFadingIn) {
this.redrawAnimation = this.window.requestAnimationFrame(this.draw);
} else {
// Element has been highlighted
this.highlightedElement.onHighlighted();
}
} else if (this.overlay.parentNode) {
// Otherwise if the overlay is there, remove it
this.document.body.removeChild(this.overlay);
if (!this.highlightedElement || !this.positionToHighlight.canHighlight()) {
return;
}
}
/**
* Checks if there as any position highlighted
* @returns {boolean}
*/
hasPositionHighlighted() {
return this.positionToHighlight.equals(this.highlightedPosition) &&
this.overlayAlpha > (this.options.opacity - 0.05);
}
// Show the overlay
this.pageOverlay.style.display = 'block';
this.highlightStage.style.display = 'block';
/**
* Removes the cloak from the given position
* i.e. cuts the chunk of layout which is over the element
* to be highlighted
*
* @param {number} posX
* @param {number} posY
* @param {number} width
* @param {number} height
*/
removeCloak({
posX = 0,
posY = 0,
width = this.overlay.width,
height = this.overlay.height,
} = {}) {
this.context.clearRect(posX, posY, width, height);
}
const elementSize = this.highlightedElement.getSize();
/**
* Adds the overlay i.e. to cover the given
* position with dark overlay
*
* @param {number} posX
* @param {number} posY
* @param {number} width
* @param {number} height
*/
addCloak({
posX = 0,
posY = 0,
width = this.overlay.width,
height = this.overlay.height,
} = {}) {
this.context.fillStyle = `rgba( 0, 0, 0, ${this.overlayAlpha} )`;
this.context.fillRect(posX, posY, width, height);
}
// Show the stage
this.highlightStage.style.display = 'block';
this.highlightStage.style.position = 'absolute';
this.highlightStage.style.width = `${elementSize.width + this.options.padding}px`;
this.highlightStage.style.height = `${elementSize.height + this.options.padding}px`;
this.highlightStage.style.top = `${this.positionToHighlight.top}px`;
this.highlightStage.style.left = `${this.positionToHighlight.left}px`;
/**
* Sets the size for the overlay
*
* @param {number|null} width
* @param {number|null} height
*/
setSize(width = null, height = null) {
// By default it is going to cover the whole page and then we will
// cut out a chunk for the element to be visible out of it
this.overlay.width = width || this.window.innerWidth;
this.overlay.height = height || this.window.innerHeight;
// Element has been highlighted
this.highlightedElement.onHighlighted();
}
/**
......@@ -270,13 +143,10 @@ export default class Overlay {
* @param {boolean} animate
*/
refresh(animate = true) {
this.setSize();
// If the highlighted element was there Cancel the
// existing animation frame if any and highlight it again
// as its position might have been changed
if (this.highlightedElement) {
this.window.cancelAnimationFrame(this.redrawAnimation);
this.highlight(this.highlightedElement, animate);
this.highlightedElement.onHighlighted();
}
......
......@@ -105,4 +105,33 @@ div#driver-popover-item {
font-weight: normal;
zoom: 1;
}
}
div#driver-page-overlay {
display: none;
width: 100%;
height: 100%;
background: black;
top: 0;
left: 0;
position: fixed;
opacity: 0.7;
pointer-events: none;
z-index: 100002 !important;
}
div#driver-highlighted-element-stage {
position: absolute;
top: 0;
left: 0;
height: 50px;
width: 300px;
background: white;
z-index: 100003 !important;
display: none;
}
.driver-highlighted-element {
z-index: 100004 !important;
position: relative;
}
\ No newline at end of file
......@@ -45,7 +45,6 @@ export default class Driver {
this.steps = []; // steps to be presented if any
this.currentStep = 0; // index for the currently highlighted step
this.onScroll = this.onScroll.bind(this);
this.onResize = this.onResize.bind(this);
this.onKeyUp = this.onKeyUp.bind(this);
this.onClick = this.onClick.bind(this);
......@@ -59,8 +58,6 @@ export default class Driver {
* @todo: add throttling in all the listeners
*/
bind() {
this.document.addEventListener('scroll', this.onScroll, false);
this.document.addEventListener('DOMMouseScroll', this.onScroll, false);
this.window.addEventListener('resize', this.onResize, false);
this.window.addEventListener('keyup', this.onKeyUp, false);
this.window.addEventListener('click', this.onClick, false);
......@@ -179,19 +176,6 @@ export default class Driver {
return this.overlay.getLastHighlightedElement();
}
/**
* Handler for the onScroll event on document
* Refreshes without animation on scroll to make sure
* that the highlighted part travels with the scroll
*/
onScroll() {
if (!this.isActivated) {
return;
}
this.overlay.refresh(false);
}
/**
* Handler for the onResize DOM event
* Refreshes with animation on scroll to make sure that
......
......@@ -18,16 +18,16 @@ module.exports = {
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre',
options: {
failOnWarning: false,
failOnError: true,
},
},
// {
// test: /\.js$/,
// exclude: /node_modules/,
// loader: 'eslint-loader',
// enforce: 'pre',
// options: {
// failOnWarning: false,
// failOnError: true,
// },
// },
{
test: /\.js$/,
exclude: /node_modules/,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册