curtain.reveal = function()

in modules/ui/curtain.js [73:226]


    curtain.reveal = function(box, text, options) {
        if (typeof box === 'string') {
            box = d3_select(box).node();
        }
        if (box && box.getBoundingClientRect) {
            box = copyBox(box.getBoundingClientRect());
        }

        options = options || {};

        var tooltipBox;
        if (options.tooltipBox) {
            tooltipBox = options.tooltipBox;
            if (typeof tooltipBox === 'string') {
                tooltipBox = d3_select(tooltipBox).node();
            }
            if (tooltipBox && tooltipBox.getBoundingClientRect) {
                tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
            }
        } else {
            tooltipBox = box;
        }

        if (tooltipBox && text) {
            // pseudo markdown bold text for the instruction section..
            var parts = text.split('**');
            var html = parts[0] ? '<span>' + parts[0] + '</span>' : '';
            if (parts[1]) {
                html += '<span class="instruction">' + parts[1] + '</span>';
            }

            html = html.replace(/\*(.*?)\*/g, '<em>$1</em>');   // emphasis
            html = html.replace(/\{br\}/g, '<br/><br/>');       // linebreak

            if (options.buttonText && options.buttonCallback) {
                html += '<div class="button-section">' +
                    '<button href="#" class="button action">' + options.buttonText + '</button></div>';
            }

            var classes = 'curtain-tooltip tooltip in ' + (options.tooltipClass || '');
            tooltip
                .classed(classes, true)
                .selectAll('.tooltip-inner')
                .html(html);

            if (options.buttonText && options.buttonCallback) {
                var button = tooltip.selectAll('.button-section .button.action');
                button
                    .on('click', function() {
                        d3_event.preventDefault();
                        options.buttonCallback();
                    });
            }

            var tip = copyBox(tooltip.node().getBoundingClientRect()),
                w = window.innerWidth,
                h = window.innerHeight,
                tooltipWidth = 200,
                tooltipArrow = 5,
                side, pos;


            // hack: this will have bottom placement,
            // so need to reserve extra space for the tooltip illustration.
            if (options.tooltipClass === 'intro-mouse') {
                tip.height += 80;
            }

            // trim box dimensions to just the portion that fits in the window..
            if (tooltipBox.top + tooltipBox.height > h) {
                tooltipBox.height -= (tooltipBox.top + tooltipBox.height - h);
            }
            if (tooltipBox.left + tooltipBox.width > w) {
                tooltipBox.width -= (tooltipBox.left + tooltipBox.width - w);
            }

            // determine tooltip placement..

            if (tooltipBox.top + tooltipBox.height < 100) {
                // tooltip below box..
                side = 'bottom';
                pos = [
                    tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
                    tooltipBox.top + tooltipBox.height
                ];

            } else if (tooltipBox.top > h - 140) {
                // tooltip above box..
                side = 'top';
                pos = [
                    tooltipBox.left + tooltipBox.width / 2 - tip.width / 2,
                    tooltipBox.top - tip.height
                ];

            } else {
                // tooltip to the side of the tooltipBox..
                var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;

                if (textDirection === 'rtl') {
                    if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
                        side = 'right';
                        pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];

                    } else {
                        side = 'left';
                        pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
                    }

                } else {
                    if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
                        side = 'left';
                        pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
                    }
                    else {
                        side = 'right';
                        pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
                    }
                }
            }

            if (options.duration !== 0 || !tooltip.classed(side)) {
                tooltip.call(uiToggle(true));
            }

            tooltip
                .style('top', pos[1] + 'px')
                .style('left', pos[0] + 'px')
                .attr('class', classes + ' ' + side);


            // shift tooltip-inner if it is very close to the top or bottom edge
            // (doesn't affect the placement of the tooltip-arrow)
            var shiftY = 0;
            if (side === 'left' || side === 'right') {
                if (pos[1] < 60) {
                    shiftY = 60 - pos[1];
                }
                else if (pos[1] + tip.height > h - 100) {
                    shiftY = h - pos[1] - tip.height - 100;
                }
            }
            tooltip.selectAll('.tooltip-inner')
                .style('top', shiftY + 'px');

        } else {
            tooltip
                .classed('in', false)
                .call(uiToggle(false));
        }

        curtain.cut(box, options.duration);

        return tooltip;
    };