speech bubbles

by Avi Algaly

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.1.1/angular.min.js"></script>
<link href='http://fonts.googleapis.com/css?family=Gochi+Hand' rel='stylesheet' type='text/css'>
<div ng-app='myApp'>
    <speech-bubble bubblew="306" bubbleh="430" bubblel="20" bubblet="30" tailh="80" taill="100" audio="data/chapters/2/audio/crewBubble-Incisors.mp3">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis quis massa
        lorem, id aliquet tortor. Vestibulum vitae nisi eget dolor auctor rhoncus
        eget vitae ante. Vestibulum dictum ornare quam quis tempor. Cras nisi purus,
        tristique eleifend tempus sed, scelerisque at nisivitae!!!</speech-bubble>
</div>

CSS

.SPEECH-BUBBLE {
    font-family:"Gochi Hand";
    font-size: 1.7em;
    line-height: 1.4em;
    position: absolute;
    top: 0px;
    bottom: 0px;
    text-align: center;
    background-color: red;
    border: 1px solid #666666;
    border-radius: 15px;
    padding: 20px;
    -webkit-box-shadow: 4px 4px 0px 0px #666;
    box-shadow: 4px 4px 0px 0px #666;
}
.SPEECH-BUBBLE::before, .SPEECH-BUBBLE::after {
    content:' ';
    position: absolute;
    width: 0;
    height: 0;
    border-style: solid;
    -webkit-transform: rotate(-33deg);
    -moz-transform: rotate(-33deg);
    -ms-transform: rotate(-33deg);
    -o-transform: rotate(-33deg);
    transform: rotate(-33deg);
    border-color: white transparent transparent white;
}
/*default attributes*/
.SPEECH-BUBBLE::before {
    bottom: -70px;
    left: 84px;
    border-width: 34px 13.513513513513514px;
    border-color: #666666 transparent transparent #666666; 
}

.SPEECH-BUBBLE::after {
    bottom: -73.5px;
    left: 73.5px;
    border-width: 50px 15.015015015015015px;
}

JavaScript

angular.module('components', [])
    .directive('speechBubble', function () {
    return {
        restrict: 'E',
        scope: {

        },
        template: '<p class="SPEECH-BUBBLE" ng-transclude><audio preload="auto" ng-src="{{audio}}"></audio></p>',
        replace: true,
        transclude: true,
        link: function (scope, linkElement, attr) {
            linkElement.css('width', attr.w + 'px');
            linkElement.css('left', attr.l + 'px');
            linkElement.css('bottom', attr.b + 'px');
            var audio = $(linkElement).find('audio').get(0);
            audio.addEventListener('ended', function () {
                // TODO: This is not working on the iPad. Prevents playing back audio more than once.
                audio.currentTime = 0;
            });
            $(linkElement).click(function () {
                audio.play();
            });
            
            linkElement.css("width", attr.bubblew + "px");
            linkElement.css("height", attr.bubbleh + "px");
            linkElement.css("left", attr.bubblel + "px");
            linkElement.css("top", attr.bubblet + "px");
            attr.tailh = Number(attr.tailh);
            attr.taill = Number(attr.taill);
            linkElement.append("<style>.SPEECH-BUBBLE:after{bottom:" + (-(attr.tailh * 1.47)) + "px;left:" + (attr.taill) + "px; border-width:" + attr.tailh + "px " + (attr.tailh / 3.33) + "px}.SPEECH-BUBBLE:before{bottom:" + (-(attr.tailh * 1.40)) + "px;left:" + (attr.taill+ attr.tailh * .16) + "px; border-width:" + (attr.tailh - (attr.tailh * .32)) + "px " + ((attr.tailh - (attr.tailh * .1)) / 3.33) + "px}   </style>");
           



        }
    }

});
angular.module('myApp', ['components']);