diff --git a/index.html b/index.html index 11f00b8..29c3067 100644 --- a/index.html +++ b/index.html @@ -320,6 +320,9 @@ activeElement.getNode(); // Gets the DOM Element behind this element +
+ + diff --git a/src/core/element.js b/src/core/element.js index 4f6e545..ededa67 100644 --- a/src/core/element.js +++ b/src/core/element.js @@ -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; diff --git a/src/core/overlay.js b/src/core/overlay.js index 0e84adb..91db094 100644 --- a/src/core/overlay.js +++ b/src/core/overlay.js @@ -1,5 +1,4 @@ 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); - } + // @todo: append the elements if not there already - const overlay = this.document.createElement('canvas'); - - 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; - } + if (!this.highlightedElement || !this.positionToHighlight.canHighlight()) { + return; } - // 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), - }); + // Show the overlay + this.pageOverlay.style.display = 'block'; + this.highlightStage.style.display = 'block'; - // 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); - } + const elementSize = this.highlightedElement.getSize(); - // cancel any existing animation frames - // to avoid the overlapping of frames - this.window.cancelAnimationFrame(this.redrawAnimation); + // 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`; - // 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); - } - } - - /** - * Checks if there as any position highlighted - * @returns {boolean} - */ - hasPositionHighlighted() { - return this.positionToHighlight.equals(this.highlightedPosition) && - this.overlayAlpha > (this.options.opacity - 0.05); - } - - /** - * 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); - } - - /** - * 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); - } - - /** - * 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(); } diff --git a/src/driver.scss b/src/driver.scss index b745b92..9464499 100644 --- a/src/driver.scss +++ b/src/driver.scss @@ -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 diff --git a/src/index.js b/src/index.js index a9bf18c..2f5bda0 100644 --- a/src/index.js +++ b/src/index.js @@ -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 diff --git a/webpack.config.dev.js b/webpack.config.dev.js index 1b9ec2b..1228d87 100644 --- a/webpack.config.dev.js +++ b/webpack.config.dev.js @@ -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/,