function Advertisement(props) {
  const { centered, children, className, content, test, unit } = props

  const classes = cx(
    'ui',
    unit,
    useKeyOnly(centered, 'centered'),
    useKeyOnly(test, 'test'),
    'ad',
    className,
  )
  const rest = getUnhandledProps(Advertisement, props)
  const ElementType = getElementType(Advertisement, props)

  return (
    <ElementType {...rest} className={classes} data-text={test}>
      {childrenUtils.isNil(children) ? content : children}
    </ElementType>
  )
}

function Advertisement ( props ) { const { centered , children , className , content , test , unit } = props const classes = cx ( 'ui' , unit , useKeyOnly ( centered , 'centered' ) , useKeyOnly ( test , 'test' ) , 'ad' , className , ) const rest = getUnhandledProps ( Advertisement , props ) const ElementType = getElementType ( Advertisement , props ) return ( < ElementType { ... rest } className = { classes } data-text = { test } > { childrenUtils . isNil ( children ) ? content : children } < / ElementType > ) }

An ad displays third-party promotional content.

An ad displays third - party promotional content .


function StatisticGroup(props) {
  const { children, className, color, content, horizontal, inverted, items, size, widths } = props

  const classes = cx(
    'ui',
    color,
    size,
    useKeyOnly(horizontal, 'horizontal'),
    useKeyOnly(inverted, 'inverted'),
    useWidthProp(widths),
    'statistics',
    className,
  )
  const rest = getUnhandledProps(StatisticGroup, props)
  const ElementType = getElementType(StatisticGroup, props)

  if (!childrenUtils.isNil(children)) {
    return (
      <ElementType {...rest} className={classes}>
        {children}
      </ElementType>
    )
  }
  if (!childrenUtils.isNil(content)) {
    return (
      <ElementType {...rest} className={classes}>
        {content}
      </ElementType>
    )
  }

  return (
    <ElementType {...rest} className={classes}>
      {_.map(items, item => Statistic.create(item))}
    </ElementType>
  )
}

function StatisticGroup ( props ) { const { children , className , color , content , horizontal , inverted , items , size , widths } = props const classes = cx ( 'ui' , color , size , useKeyOnly ( horizontal , 'horizontal' ) , useKeyOnly ( inverted , 'inverted' ) , useWidthProp ( widths ) , 'statistics' , className , ) const rest = getUnhandledProps ( StatisticGroup , props ) const ElementType = getElementType ( StatisticGroup , props ) if ( ! childrenUtils . isNil ( children ) ) { return ( < ElementType { ... rest } className = { classes } > { children } < / ElementType > ) } if ( ! childrenUtils . isNil ( content ) ) { return ( < ElementType { ... rest } className = { classes } > { content } < / ElementType > ) } return ( < ElementType { ... rest } className = { classes } > { _ . map ( items , item => Statistic . create ( item ) ) } < / ElementType > ) }


function Statistic(props) {
  const {
    children,
    className,
    color,
    content,
    floated,
    horizontal,
    inverted,
    label,
    size,
    text,
    value,
  } = props

  const classes = cx(
    'ui',
    color,
    size,
    useValueAndKey(floated, 'floated'),
    useKeyOnly(horizontal, 'horizontal'),
    useKeyOnly(inverted, 'inverted'),
    'statistic',
    className,
  )
  const rest = getUnhandledProps(Statistic, props)
  const ElementType = getElementType(Statistic, props)

  if (!childrenUtils.isNil(children)) {
    return (
      <ElementType {...rest} className={classes}>
        {children}
      </ElementType>
    )
  }
  if (!childrenUtils.isNil(content)) {
    return (
      <ElementType {...rest} className={classes}>
        {content}
      </ElementType>
    )
  }

  return (
    <ElementType {...rest} className={classes}>
      {StatisticValue.create(value, {
        defaultProps: { text },
        autoGenerateKey: false,
      })}
      {StatisticLabel.create(label, { autoGenerateKey: false })}
    </ElementType>
  )
}

function Statistic ( props ) { const { children , className , color , content , floated , horizontal , inverted , label , size , text , value , } = props const classes = cx ( 'ui' , color , size , useValueAndKey ( floated , 'floated' ) , useKeyOnly ( horizontal , 'horizontal' ) , useKeyOnly ( inverted , 'inverted' ) , 'statistic' , className , ) const rest = getUnhandledProps ( Statistic , props ) const ElementType = getElementType ( Statistic , props ) if ( ! childrenUtils . isNil ( children ) ) { return ( < ElementType { ... rest } className = { classes } > { children } < / ElementType > ) } if ( ! childrenUtils . isNil ( content ) ) { return ( < ElementType { ... rest } className = { classes } > { content } < / ElementType > ) } return ( < ElementType { ... rest } className = { classes } > { StatisticValue . create ( value , { defaultProps : { text } , autoGenerateKey : false , } ) } { StatisticLabel . create ( label , { autoGenerateKey : false } ) } < / ElementType > ) }

A statistic emphasizes the current value of an attribute.

A statistic emphasizes the current value of an attribute .


function SegmentGroup(props) {
  const { children, className, compact, content, horizontal, piled, raised, size, stacked } = props

  const classes = cx(
    'ui',
    size,
    useKeyOnly(compact, 'compact'),
    useKeyOnly(horizontal, 'horizontal'),
    useKeyOnly(piled, 'piled'),
    useKeyOnly(raised, 'raised'),
    useKeyOnly(stacked, 'stacked'),
    'segments',
    className,
  )
  const rest = getUnhandledProps(SegmentGroup, props)
  const ElementType = getElementType(SegmentGroup, props)

  return (
    <ElementType {...rest} className={classes}>
      {childrenUtils.isNil(children) ? content : children}
    </ElementType>
  )
}

function SegmentGroup ( props ) { const { children , className , compact , content , horizontal , piled , raised , size , stacked } = props const classes = cx ( 'ui' , size , useKeyOnly ( compact , 'compact' ) , useKeyOnly ( horizontal , 'horizontal' ) , useKeyOnly ( piled , 'piled' ) , useKeyOnly ( raised , 'raised' ) , useKeyOnly ( stacked , 'stacked' ) , 'segments' , className , ) const rest = getUnhandledProps ( SegmentGroup , props ) const ElementType = getElementType ( SegmentGroup , props ) return ( < ElementType { ... rest } className = { classes } > { childrenUtils . isNil ( children ) ? content : children } < / ElementType > ) }

A group of segments can be formatted to appear together.

A group of segments can be formatted to appear together .


function TableHeaderCell(props) {
  const { as, className, sorted } = props
  const classes = cx(useValueAndKey(sorted, 'sorted'), className)
  const rest = getUnhandledProps(TableHeaderCell, props)

  return <TableCell {...rest} as={as} className={classes} />
}

function TableHeaderCell ( props ) { const { as , className , sorted } = props const classes = cx ( useValueAndKey ( sorted , 'sorted' ) , className ) const rest = getUnhandledProps ( TableHeaderCell , props ) return < TableCell { ... rest } as = { as } className = { classes } / > }


function Feed(props) {
  const { children, className, events, size } = props

  const classes = cx('ui', size, 'feed', className)
  const rest = getUnhandledProps(Feed, props)
  const ElementType = getElementType(Feed, props)

  if (!childrenUtils.isNil(children)) {
    return (
      <ElementType {...rest} className={classes}>
        {children}
      </ElementType>
    )
  }

  const eventElements = _.map(events, (eventProps) => {
    const { childKey, date, meta, summary, ...eventData } = eventProps
    const finalKey = childKey || [date, meta, summary].join('-')

    return <FeedEvent date={date} key={finalKey} meta={meta} summary={summary} {...eventData} />
  })

  return (
    <ElementType {...rest} className={classes}>
      {eventElements}
    </ElementType>
  )
}

function Feed ( props ) { const { children , className , events , size } = props const classes = cx ( 'ui' , size , 'feed' , className ) const rest = getUnhandledProps ( Feed , props ) const ElementType = getElementType ( Feed , props ) if ( ! childrenUtils . isNil ( children ) ) { return ( < ElementType { ... rest } className = { classes } > { children } < / ElementType > ) } const eventElements = _ . map ( events , ( eventProps ) => { const { childKey , date , meta , summary , ... eventData } = eventProps const finalKey = childKey || [ date , meta , summary ] . join ( '-' ) return < FeedEvent date = { date } key = { finalKey } meta = { meta } summary = { summary } { ... eventData } / > } ) return ( < ElementType { ... rest } className = { classes } > { eventElements } < / ElementType > ) }

A feed presents user activity chronologically.

A feed presents user activity chronologically .


function LabelGroup(props) {
  const { children, circular, className, color, content, size, tag } = props

  const classes = cx(
    'ui',
    color,
    size,
    useKeyOnly(circular, 'circular'),
    useKeyOnly(tag, 'tag'),
    'labels',
    className,
  )
  const rest = getUnhandledProps(LabelGroup, props)
  const ElementType = getElementType(LabelGroup, props)

  return (
    <ElementType {...rest} className={classes}>
      {childrenUtils.isNil(children) ? content : children}
    </ElementType>
  )
}

function LabelGroup ( props ) { const { children , circular , className , color , content , size , tag } = props const classes = cx ( 'ui' , color , size , useKeyOnly ( circular , 'circular' ) , useKeyOnly ( tag , 'tag' ) , 'labels' , className , ) const rest = getUnhandledProps ( LabelGroup , props ) const ElementType = getElementType ( LabelGroup , props ) return ( < ElementType { ... rest } className = { classes } > { childrenUtils . isNil ( children ) ? content : children } < / ElementType > ) }


function FeedExtra(props) {
  const { children, className, content, images, text } = props

  const classes = cx(
    useKeyOnly(images, 'images'),
    useKeyOnly(content || text, 'text'),
    'extra',
    className,
  )
  const rest = getUnhandledProps(FeedExtra, props)
  const ElementType = getElementType(FeedExtra, props)

  if (!childrenUtils.isNil(children)) {
    return (
      <ElementType {...rest} className={classes}>
        {children}
      </ElementType>
    )
  }

  // TODO need a "collection factory" to handle creating multiple image elements and their keys
  const imageElements = _.map(images, (image, index) => {
    const key = [index, image].join('-')
    return createHTMLImage(image, { key })
  })

  return (
    <ElementType {...rest} className={classes}>
      {content}
      {imageElements}
    </ElementType>
  )
}


function DropdownDivider(props) {
  const { className } = props
  const classes = cx('divider', className)
  const rest = getUnhandledProps(DropdownDivider, props)
  const ElementType = getElementType(DropdownDivider, props)

  return <ElementType {...rest} className={classes} />
}

function DropdownDivider ( props ) { const { className } = props const classes = cx ( 'divider' , className ) const rest = getUnhandledProps ( DropdownDivider , props ) const ElementType = getElementType ( DropdownDivider , props ) return < ElementType { ... rest } className = { classes } / > }

A dropdown menu can contain dividers to separate related content.

A dropdown menu can contain dividers to separate related content .


function FeedSummary(props) {
  const { children, className, content, date, user } = props

  const classes = cx('summary', className)
  const rest = getUnhandledProps(FeedSummary, props)
  const ElementType = getElementType(FeedSummary, props)

  if (!childrenUtils.isNil(children)) {
    return (
      <ElementType {...rest} className={classes}>
        {children}
      </ElementType>
    )
  }

  return (
    <ElementType {...rest} className={classes}>
      {createShorthand(FeedUser, val => ({ content: val }), user, { autoGenerateKey: false })}
      {content}
      {createShorthand(FeedDate, val => ({ content: val }), date, { autoGenerateKey: false })}
    </ElementType>
  )
}

function FeedSummary ( props ) { const { children , className , content , date , user } = props const classes = cx ( 'summary' , className ) const rest = getUnhandledProps ( FeedSummary , props ) const ElementType = getElementType ( FeedSummary , props ) if ( ! childrenUtils . isNil ( children ) ) { return ( < ElementType { ... rest } className = { classes } > { children } < / ElementType > ) } return ( < ElementType { ... rest } className = { classes } > { createShorthand ( FeedUser , val => ( { content : val } ) , user , { autoGenerateKey : false } ) } { content } { createShorthand ( FeedDate , val => ( { content : val } ) , date , { autoGenerateKey : false } ) } < / ElementType > ) }


function StepContent(props) {
  const { children, className, content, description, title } = props
  const classes = cx('content', className)
  const rest = getUnhandledProps(StepContent, props)
  const ElementType = getElementType(StepContent, props)

  if (!childrenUtils.isNil(children)) {
    return (
      <ElementType {...rest} className={classes}>
        {children}
      </ElementType>
    )
  }
  if (!childrenUtils.isNil(content)) {
    return (
      <ElementType {...rest} className={classes}>
        {content}
      </ElementType>
    )
  }

  return (
    <ElementType {...rest} className={classes}>
      {StepTitle.create(title, { autoGenerateKey: false })}
      {StepDescription.create(description, { autoGenerateKey: false })}
    </ElementType>
  )
}

function StepContent ( props ) { const { children , className , content , description , title } = props const classes = cx ( 'content' , className ) const rest = getUnhandledProps ( StepContent , props ) const ElementType = getElementType ( StepContent , props ) if ( ! childrenUtils . isNil ( children ) ) { return ( < ElementType { ... rest } className = { classes } > { children } < / ElementType > ) } if ( ! childrenUtils . isNil ( content ) ) { return ( < ElementType { ... rest } className = { classes } > { content } < / ElementType > ) } return ( < ElementType { ... rest } className = { classes } > { StepTitle . create ( title , { autoGenerateKey : false } ) } { StepDescription . create ( description , { autoGenerateKey : false } ) } < / ElementType > ) }


function Image(props) {
  const {
    avatar,
    bordered,
    centered,
    children,
    circular,
    className,
    content,
    dimmer,
    disabled,
    floated,
    fluid,
    hidden,
    href,
    inline,
    label,
    rounded,
    size,
    spaced,
    verticalAlign,
    wrapped,
    ui,
  } = props

  const classes = cx(
    useKeyOnly(ui, 'ui'),
    size,
    useKeyOnly(avatar, 'avatar'),
    useKeyOnly(bordered, 'bordered'),
    useKeyOnly(circular, 'circular'),
    useKeyOnly(centered, 'centered'),
    useKeyOnly(disabled, 'disabled'),
    useKeyOnly(fluid, 'fluid'),
    useKeyOnly(hidden, 'hidden'),
    useKeyOnly(inline, 'inline'),
    useKeyOnly(rounded, 'rounded'),
    useKeyOrValueAndKey(spaced, 'spaced'),
    useValueAndKey(floated, 'floated'),
    useVerticalAlignProp(verticalAlign, 'aligned'),
    'image',
    className,
  )
  const rest = getUnhandledProps(Image, props)
  const [imgTagProps, rootProps] = partitionHTMLProps(rest, { htmlProps: htmlImageProps })
  const ElementType = getElementType(Image, props, () => {
    if (
      !_.isNil(dimmer) ||
      !_.isNil(label) ||
      !_.isNil(wrapped) ||
      !childrenUtils.isNil(children)
    ) {
      return 'div'
    }
  })

  if (!childrenUtils.isNil(children)) {
    return (
      <ElementType {...rest} className={classes}>
        {children}
      </ElementType>
    )
  }
  if (!childrenUtils.isNil(content)) {
    return (
      <ElementType {...rest} className={classes}>
        {content}
      </ElementType>
    )
  }

  if (ElementType === 'img') {
    return <ElementType {...rootProps} {...imgTagProps} className={classes} />
  }
  return (
    <ElementType {...rootProps} className={classes} href={href}>
      {Dimmer.create(dimmer, { autoGenerateKey: false })}
      {Label.create(label, { autoGenerateKey: false })}
      <img {...imgTagProps} />
    </ElementType>
  )
}

function Image ( props ) { const { avatar , bordered , centered , children , circular , className , content , dimmer , disabled , floated , fluid , hidden , href , inline , label , rounded , size , spaced , verticalAlign , wrapped , ui , } = props const classes = cx ( useKeyOnly ( ui , 'ui' ) , size , useKeyOnly ( avatar , 'avatar' ) , useKeyOnly ( bordered , 'bordered' ) , useKeyOnly ( circular , 'circular' ) , useKeyOnly ( centered , 'centered' ) , useKeyOnly ( disabled , 'disabled' ) , useKeyOnly ( fluid , 'fluid' ) , useKeyOnly ( hidden , 'hidden' ) , useKeyOnly ( inline , 'inline' ) , useKeyOnly ( rounded , 'rounded' ) , useKeyOrValueAndKey ( spaced , 'spaced' ) , useValueAndKey ( floated , 'floated' ) , useVerticalAlignProp ( verticalAlign , 'aligned' ) , 'image' , className , ) const rest = getUnhandledProps ( Image , props ) const [ imgTagProps , rootProps ] = partitionHTMLProps ( rest , { htmlProps : htmlImageProps } ) const ElementType = getElementType ( Image , props , ( ) => { if ( ! _ . isNil ( dimmer ) || ! _ . isNil ( label ) || ! _ . isNil ( wrapped ) || ! childrenUtils . isNil ( children ) ) { return 'div' } } ) if ( ! childrenUtils . isNil ( children ) ) { return ( < ElementType { ... rest } className = { classes } > { children } < / ElementType > ) } if ( ! childrenUtils . isNil ( content ) ) { return ( < ElementType { ... rest } className = { classes } > { content } < / ElementType > ) } if ( ElementType === 'img' ) { return < ElementType { ... rootProps } { ... imgTagProps } className = { classes } / > } return ( < ElementType { ... rootProps } className = { classes } href = { href } > { Dimmer . create ( dimmer , { autoGenerateKey : false } ) } { Label . create ( label , { autoGenerateKey : false } ) } < img { ... imgTagProps } / > < / ElementType > ) }

An image is a graphic representation of something.
@see Icon

An image is a graphic representation of something .


function(canvas) {
        var context = canvas.getContext('2d'),
            devicePixelRatio = window.devicePixelRatio || 1,
            backingStorePixelRatio = context.webkitBackingStorePixelRatio || context.mozBackingStorePixelRatio
                                      || context.msBackingStorePixelRatio || context.oBackingStorePixelRatio
                                      || context.backingStorePixelRatio || 1;

        return devicePixelRatio / backingStorePixelRatio;
    }

function ( canvas ) { var context = canvas . getContext ( '2d' ) , devicePixelRatio = window . devicePixelRatio || 1 , backingStorePixelRatio = context . webkitBackingStorePixelRatio || context . mozBackingStorePixelRatio || context . msBackingStorePixelRatio || context . oBackingStorePixelRatio || context . backingStorePixelRatio || 1 ; return devicePixelRatio / backingStorePixelRatio ; }

Gets the pixel ratio of the canvas.
@method _getPixelRatio
@private
@param {HTMLElement} canvas
@return {Number} pixel ratio


function(render, background) {
        var cssBackground = background;

        if (/(jpg|gif|png)$/.test(background))
            cssBackground = 'url(' + background + ')';

        render.canvas.style.background = cssBackground;
        render.canvas.style.backgroundSize = "contain";
        render.currentBackground = background;
    }

function ( render , background ) { var cssBackground = background ; if ( / (jpg|gif|png)$ / . test ( background ) ) cssBackground = 'url(' + background + ')' ; render . canvas . style . background = cssBackground ; render . canvas . style . backgroundSize = "contain" ; render . currentBackground = background ; }

Applies the background to the canvas using CSS.
@method applyBackground
@private
@param {render} render
@param {string} background

Applies the background to the canvas using CSS .


function(render, body) {
        var bodyRender = body.render,
            texturePath = bodyRender.sprite.texture,
            texture = _getTexture(render, texturePath),
            sprite = new PIXI.Sprite(texture);

        sprite.anchor.x = body.render.sprite.xOffset;
        sprite.anchor.y = body.render.sprite.yOffset;

        return sprite;
    }

function ( render , body ) { var bodyRender = body . render , texturePath = bodyRender . sprite . texture , texture = _getTexture ( render , texturePath ) , sprite = new PIXI . Sprite ( texture ) ; sprite . anchor . x = body . render . sprite . xOffset ; sprite . anchor . y = body . render . sprite . yOffset ; return sprite ; }

Creates a body sprite
@method _createBodySprite
@private
@param {RenderPixi} render
@param {body} body
@return {PIXI.Sprite} sprite
@deprecated


function(render, body) {
        var bodyRender = body.render,
            options = render.options,
            primitive = new PIXI.Graphics(),
            fillStyle = Common.colorToNumber(bodyRender.fillStyle),
            strokeStyle = Common.colorToNumber(bodyRender.strokeStyle),
            strokeStyleIndicator = Common.colorToNumber(bodyRender.strokeStyle),
            strokeStyleWireframe = Common.colorToNumber('#bbb'),
            strokeStyleWireframeIndicator = Common.colorToNumber('#CD5C5C'),
            part;

        primitive.clear();

        // handle compound parts
        for (var k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
            part = body.parts[k];

            if (!options.wireframes) {
                primitive.beginFill(fillStyle, 1);
                primitive.lineStyle(bodyRender.lineWidth, strokeStyle, 1);
            } else {
                primitive.beginFill(0, 0);
                primitive.lineStyle(1, strokeStyleWireframe, 1);
            }

            primitive.moveTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);

            for (var j = 1; j < part.vertices.length; j++) {
                primitive.lineTo(part.vertices[j].x - body.position.x, part.vertices[j].y - body.position.y);
            }

            primitive.lineTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);

            primitive.endFill();

            // angle indicator
            if (options.showAngleIndicator || options.showAxes) {
                primitive.beginFill(0, 0);

                if (options.wireframes) {
                    primitive.lineStyle(1, strokeStyleWireframeIndicator, 1);
                } else {
                    primitive.lineStyle(1, strokeStyleIndicator);
                }

                primitive.moveTo(part.position.x - body.position.x, part.position.y - body.position.y);
                primitive.lineTo(((part.vertices[0].x + part.vertices[part.vertices.length-1].x) / 2 - body.position.x),
                                 ((part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2 - body.position.y));

                primitive.endFill();
            }
        }

        return primitive;
    }

function
(
render
,
body
)
{
var
bodyRender
=
body
.
render
,
options
=
render
.
options
,
primitive
=
new
PIXI
.
Graphics
(
)
,
fillStyle
=
Common
.
colorToNumber
(
bodyRender
.
fillStyle
)
,
strokeStyle
=
Common
.
colorToNumber
(
bodyRender
.
strokeStyle
)
,
strokeStyleIndicator
=
Common
.
colorToNumber
(
bodyRender
.
strokeStyle
)
,
strokeStyleWireframe
=
Common
.
colorToNumber
(
'#bbb'
)
,
strokeStyleWireframeIndicator
=
Common
.
colorToNumber
(
'#CD5C5C'
)
,
part
;
primitive
.
clear
(
)
;
// handle compound parts
for
(
var
k
=
body
.
parts
.
length
>
1
1
:
0
;
k
<
body
.
parts
.
length
;
k
++
)
{
part
=
body
.
parts
[
k
]
;
if
(
!
options
.
wireframes
)
{
primitive
.
beginFill
(
fillStyle
,
1
)
;
primitive
.
lineStyle
(
bodyRender
.
lineWidth
,
strokeStyle
,
1
)
;
}
else
{
primitive
.
beginFill
(
0
,
0
)
;
primitive
.
lineStyle
(
1
,
strokeStyleWireframe
,
1
)
;
}
primitive
.
moveTo
(
part
.
vertices
[
0
]
.
x
body
.
position
.
x
,
part
.
vertices
[
0
]
.
y
body
.
position
.
y
)
;
for
(
var
j
=
1
;
j
<
part
.
vertices
.
length
;
j
++
)
{
primitive
.
lineTo
(
part
.
vertices
[
j
]
.
x
body
.
position
.
x
,
part
.
vertices
[
j
]
.
y
body
.
position
.
y
)
;
}
primitive
.
lineTo
(
part
.
vertices
[
0
]
.
x
body
.
position
.
x
,
part
.
vertices
[
0
]
.
y
body
.
position
.
y
)
;
primitive
.
endFill
(
)
;
// angle indicator
if
(
options
.
showAngleIndicator
||
options
.
showAxes
)
{
primitive
.
beginFill
(
0
,
0
)
;
if
(
options
.
wireframes
)
{
primitive
.
lineStyle
(
1
,
strokeStyleWireframeIndicator
,
1
)
;
}
else
{
primitive
.
lineStyle
(
1
,
strokeStyleIndicator
)
;
}
primitive
.
moveTo
(
part
.
position
.
x
body
.
position
.
x
,
part
.
position
.
y
body
.
position
.
y
)
;
primitive
.
lineTo
(
(
(
part
.
vertices
[
0
]
.
x
+
part
.
vertices
[
part
.
vertices
.
length
1
]
.
x
)
/
2
body
.
position
.
x
)
,
(
(
part
.
vertices
[
0
]
.
y
+
part
.
vertices
[
part
.
vertices
.
length
1
]
.
y
)
/
2
body
.
position
.
y
)
)
;
primitive
.
endFill
(
)
;
}
}
return
primitive
;
}

Creates a body primitive
@method _createBodyPrimitive
@private
@param {RenderPixi} render
@param {body} body
@return {PIXI.Graphics} graphics
@deprecated


function(body, options) {
        options = options || {};

        // init required properties (order is important)
        Body.set(body, {
            bounds: body.bounds || Bounds.create(body.vertices),
            positionPrev: body.positionPrev || Vector.clone(body.position),
            anglePrev: body.anglePrev || body.angle,
            vertices: body.vertices,
            parts: body.parts || [body],
            isStatic: body.isStatic,
            isSleeping: body.isSleeping,
            parent: body.parent || body
        });

        Vertices.rotate(body.vertices, body.angle, body.position);
        Axes.rotate(body.axes, body.angle);
        Bounds.update(body.bounds, body.vertices, body.velocity);

        // allow options to override the automatically calculated properties
        Body.set(body, {
            axes: options.axes || body.axes,
            area: options.area || body.area,
            mass: options.mass || body.mass,
            inertia: options.inertia || body.inertia
        });

        // render properties
        var defaultFillStyle = (body.isStatic ? '#2e2b44' : Common.choose(['#006BA6', '#0496FF', '#FFBC42', '#D81159', '#8F2D56'])),
            defaultStrokeStyle = '#000';
        body.render.fillStyle = body.render.fillStyle || defaultFillStyle;
        body.render.strokeStyle = body.render.strokeStyle || defaultStrokeStyle;
        body.render.sprite.xOffset += -(body.bounds.min.x - body.position.x) / (body.bounds.max.x - body.bounds.min.x);
        body.render.sprite.yOffset += -(body.bounds.min.y - body.position.y) / (body.bounds.max.y - body.bounds.min.y);
    }

Initialises body properties.
@method _initProperties
@private
@param {body} body
@param {} [options]


async function createPages({ actions, graphql }) {
	const retrieveMarkdownPages = () =>
		graphql(`
			{
				allMarkdownRemark(limit: 1000) {
					edges {
						node {
							frontmatter {
								path
							}
						}
					}
				}
			}
		`)

	const exampleTemplate = path.resolve(`src/templates/exampleTemplate.tsx`)
	const docTemplate = path.resolve(`src/templates/docTemplate.tsx`)
	const result = await retrieveMarkdownPages()

	if (result.errors) {
		console.error('graphql error', result.errors)
		throw new Error('Error invoking graphql for pages')
	}

	result.data.allMarkdownRemark.edges.forEach(({ node }) => {
		const {
			frontmatter: { path: pagePath },
		} = node
		const category = (pagePath || '/').split('/').filter(t => !!t)[0]
		const isExample = category === 'examples'
		console.log(`create page for ${pagePath} - type is ${category}`)
		actions.createPage({
			path: pagePath,
			component: isExample ? exampleTemplate : docTemplate,
			context: {}, // additional data can be passed via context
		})
	})
}

Dynamically creates pages in the static website


function isWindow(val) {
  if (typeof val !== "object") {
    return false;
  }
  const wrapper = idlUtils.wrapperForImpl(val);
  if (typeof wrapper === "object") {
    return wrapper === wrapper._globalProxy;
  }

  // `val` may be either impl or wrapper currently, because webidl2js currently unwraps Window objects (and their global
  // proxies) to their underlying EventTargetImpl during conversion, which is not what we want. But at the same time,
  // some internal usage call this constructor with the actual global proxy.
  return isWindow(idlUtils.implForWrapper(val));
}

Until webidl2js gains support for checking for Window, this would have to do.

Until webidl2js gains support for checking for Window this would have to do .


function normalizeEventHandlerOptions(options, defaultBoolKeys) {
  const returnValue = {};

  // no need to go further here
  if (typeof options === "boolean" || options === null || typeof options === "undefined") {
    returnValue.capture = Boolean(options);
    return returnValue;
  }

  // non objects options so we typecast its value as "capture" value
  if (typeof options !== "object") {
    returnValue.capture = Boolean(options);
    // at this point we don't need to loop the "capture" key anymore
    defaultBoolKeys = defaultBoolKeys.filter(k => k !== "capture");
  }

  for (const key of defaultBoolKeys) {
    returnValue[key] = Boolean(options[key]);
  }

  return returnValue;
}

Normalize the event listeners options argument in order to get always a valid options object
@param   {Object} options         - user defined options
@param   {Array} defaultBoolKeys  - boolean properties that should belong to the options object
@returns {Object} object containing at least the "defaultBoolKeys"


function sammary() {
  const nodeFn = function ({ parentPaths, lang, item, isDir, result }) {
    const navTitle = generateNavTitle({ parentPaths, item, sign: isDir ? '-' : '*', lang });
    result.push(navTitle);
  };

  langs.forEach(dir => {
    const SUMMARY = 'SUMMARY.md';
    const targetFile = path.join(docsDir, `${dir}/${SUMMARY}`);

    const result = walk({
      catalog: docConfig.catalog,
      lang: dir,
      result: [],
      parentPaths: [],
      fn: nodeFn
    });

    if (result && result.length) {
      result.unshift('# whistle\n');
      fs.writeFileSync(targetFile, result.join('\n'));
    }
  });
}

function
sammary
(
)
{
const
nodeFn
=
function
(
{
parentPaths
,
lang
,
item
,
isDir
,
result
}
)
{
const
navTitle
=
generateNavTitle
(
{
parentPaths
,
item
,
sign
:
isDir
'-'
:
'*'
,
lang
}
)
;
result
.
push
(
navTitle
)
;
}
;
langs
.
forEach
(
dir
=>
{
const
SUMMARY
=
'SUMMARY.md'
;
const
targetFile
=
path
.
join
(
docsDir
,
`
${
dir
}
${
SUMMARY
}
`
)
;
const
result
=
walk
(
{
catalog
:
docConfig
.
catalog
,
lang
:
dir
,
result
:
[
]
,
parentPaths
:
[
]
,
fn
:
nodeFn
}
)
;
if
(
result
&&
result
.
length
)
{
result
.
unshift
(
'# whistle\n'
)
;
fs
.
writeFileSync
(
targetFile
,
result
.
join
(
'\n'
)
)
;
}
}
)
;
}


function createItemString(data, limit) {
  var count = 0;
  var hasMore = false;
  if ((0, _isSafeInteger2['default'])(data.size)) {
    count = data.size;
  } else {
    for (var _iterator = data, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : (0, _getIterator3['default'])(_iterator);;) {
      var _ref;

      if (_isArray) {
        if (_i >= _iterator.length) break;
        _ref = _iterator[_i++];
      } else {
        _i = _iterator.next();
        if (_i.done) break;
        _ref = _i.value;
      }

      var entry = _ref;
      // eslint-disable-line no-unused-vars
      if (limit && count + 1 > limit) {
        hasMore = true;
        break;
      }
      count += 1;
    }
  }
  return '' + (hasMore ? '>' : '') + count + ' ' + (count !== 1 ? 'entries' : 'entry');
}

function
createItemString
(
data
,
limit
)
{
var
count
=
0
;
var
hasMore
=
false
;
if
(
(
0
,
_isSafeInteger2
[
'default'
]
)
(
data
.
size
)
)
{
count
=
data
.
size
;
}
else
{
for
(
var
_iterator
=
data
,
_isArray
=
Array
.
isArray
(
_iterator
)
,
_i
=
0
,
_iterator
=
_isArray
_iterator
:
(
0
,
_getIterator3
[
'default'
]
)
(
_iterator
)
;
;
)
{
var
_ref
;
if
(
_isArray
)
{
if
(
_i
>=
_iterator
.
length
)
break
;
_ref
=
_iterator
[
_i
++
]
;
}
else
{
_i
=
_iterator
.
next
(
)
;
if
(
_i
.
done
)
break
;
_ref
=
_i
.
value
;
}
var
entry
=
_ref
;
// eslint-disable-line no-unused-vars
if
(
limit
&&
count
+
1
>
limit
)
{
hasMore
=
true
;
break
;
}
count
+=
1
;
}
}
return
''
+
(
hasMore
'>'
:
''
)
+
count
+
' '
+
(
count
!==
1
'entries'
:
'entry'
)
;
}

Returns the "n Items" string for this node, generating and caching it if it hasn't been created yet.

Returns the n Items string for this node generating and caching it if it hasn t been created yet .


function kw(name, options = {}) {
  options.keyword = name
  return keywords[name] = new TokenType(name, options)
}

function kw ( name , options = { } ) { options . keyword = name return keywords [ name ] = new TokenType ( name , options ) }

Succinct definitions of keyword token types


function isInAstralSet(code, set) {
  let pos = 0x10000
  for (let i = 0; i < set.length; i += 2) {
    pos += set[i]
    if (pos > code) return false
    pos += set[i + 1]
    if (pos >= code) return true
  }
}

function isInAstralSet ( code , set ) { let pos = 0x10000 for ( let i = 0 ; i < set . length ; i += 2 ) { pos += set [ i ] if ( pos > code ) return false pos += set [ i + 1 ] if ( pos >= code ) return true } }

This has a complexity linear to the value of the code. The assumption is that looking up astral identifier characters is rare.

This has a complexity linear to the value of the code . The assumption is that looking up astral identifier characters is rare .


function transformMetadata(metadata) {
  const namesRegEx = new RegExp(
    metadata.tokens.map(token => token.name).join('|'),
    'g'
  );

  const replaceMap = {};
  metadata.tokens.map(token => {
    replaceMap[token.name] = formatTokenName(token.name);
  });

  metadata.tokens.forEach((token, i) => {
    // interactive01 to `$interactive-01`
    if (token.role) {
      token.role.forEach((role, j) => {
        metadata.tokens[i].role[j] = role.replace(namesRegEx, match => {
          return '`$' + replaceMap[match] + '`';
        });
      });
    }

    // brand01 to brand-01
    if (token.alias) {
      token.alias = formatTokenName(token.alias);
    }
  });

  return metadata;
}

function
transformMetadata
(
metadata
)
{
const
namesRegEx
=
new
RegExp
(
metadata
.
tokens
.
map
(
token
=>
token
.
name
)
.
join
(
'|'
)
,
'g'
)
;
const
replaceMap
=
{
}
;
metadata
.
tokens
.
map
(
token
=>
{
replaceMap
[
token
.
name
]
=
formatTokenName
(
token
.
name
)
;
}
)
;
metadata
.
tokens
.
forEach
(
(
token
,
i
)
=>
{
// interactive01 to `$interactive-01`
if
(
token
.
role
)
{
token
.
role
.
forEach
(
(
role
,
j
)
=>
{
metadata
.
tokens
[
i
]
.
role
[
j
]
=
role
.
replace
(
namesRegEx
,
match
=>
{
return
'`$'
+
replaceMap
[
match
]
+
'`'
;
}
)
;
}
)
;
}
// brand01 to brand-01
if
(
token
.
alias
)
{
token
.
alias
=
formatTokenName
(
token
.
alias
)
;
}
}
)
;
return
metadata
;
}

Transform token names to formats expected by Sassdoc for descriptions and
aliases
@param {Object} - token metadata
@return {Object} token metadata


async function findPackageFor(filepath) {
  let directory = filepath;

  while (directory !== '/') {
    const directoryToSearch = path.dirname(directory);
    const files = await fs.readdir(directoryToSearch);

    if (files.indexOf('package.json') !== -1) {
      const packageJson = await fs.readJson(
        path.join(directoryToSearch, 'package.json')
      );
      return packageJson.name;
    }

    directory = path.resolve(directory, '..');
  }

  throw new Error(`Unable to find package for: ${filepath}`);
}

async function findPackageFor ( filepath ) { let directory = filepath ; while ( directory !== '/' ) { const directoryToSearch = path . dirname ( directory ) ; const files = await fs . readdir ( directoryToSearch ) ; if ( files . indexOf ( 'package.json' ) !== - 1 ) { const packageJson = await fs . readJson ( path . join ( directoryToSearch , 'package.json' ) ) ; return packageJson . name ; } directory = path . resolve ( directory , '..' ) ; } throw new Error ( ` ${ filepath } ` ) ; }

Rough heuristic used to find the package name for a given file. Idea is to move upwards looking for directories that have a `package.json` file. Once we find one, we report back the name from that file.

Rough heuristic used to find the package name for a given file . Idea is to move upwards looking for directories that have a package . json file . Once we find one we report back the name from that file .


function svgToggleClass(svg, name, forceAdd) {
  const list = svg
    .getAttribute('class')
    .trim()
    .split(/\s+/);
  const uniqueList = Object.keys(list.reduce((o, item) => Object.assign(o, { [item]: 1 }), {}));
  const index = uniqueList.indexOf(name);
  const found = index >= 0;
  const add = forceAdd === undefined ? !found : forceAdd;

  if (found === !add) {
    if (add) {
      uniqueList.push(name);
    } else {
      uniqueList.splice(index, 1);
    }
    svg.setAttribute('class', uniqueList.join(' '));
  }
}

function
svgToggleClass
(
svg
,
name
,
forceAdd
)
{
const
list
=
svg
.
getAttribute
(
'class'
)
.
trim
(
)
.
split
(
/
\s+
/
)
;
const
uniqueList
=
Object
.
keys
(
list
.
reduce
(
(
o
,
item
)
=>
Object
.
assign
(
o
,
{
[
item
]
:
1
}
)
,
{
}
)
)
;
const
index
=
uniqueList
.
indexOf
(
name
)
;
const
found
=
index
>=
0
;
const
add
=
forceAdd
===
undefined
!
found
:
forceAdd
;
if
(
found
===
!
add
)
{
if
(
add
)
{
uniqueList
.
push
(
name
)
;
}
else
{
uniqueList
.
splice
(
index
,
1
)
;
}
svg
.
setAttribute
(
'class'
,
uniqueList
.
join
(
' '
)
)
;
}
}

Copyright IBM Corp. 2016, 2018

This source code is licensed under the Apache-2.0 license found in the
LICENSE file in the root directory of this source tree.


async function flatMapAsync(source, mapFn) {
  const results = await Promise.all(source.map(mapFn));
  return results.reduce((acc, result) => acc.concat(result), []);
}

async function flatMapAsync ( source , mapFn ) { const results = await Promise . all ( source . map ( mapFn ) ) ; return results . reduce ( ( acc , result ) => acc . concat ( result ) , [ ] ) ; }

Copyright IBM Corp. 2018, 2018

This source code is licensed under the Apache-2.0 license found in the
LICENSE file in the root directory of this source tree.


async function createJson(sourceDir, config) {
  config = config || {};

  return sassdoc.parse(sourceDir, config).then(
    data => {
      return data;
    },
    err => {
      console.error(err);
    }
  );
}

async function createJson ( sourceDir , config ) { config = config || { } ; return sassdoc . parse ( sourceDir , config ) . then ( data => { return data ; } , err => { console . error ( err ) ; } ) ; }

Create a JSON file of documented Sass items
@see {@link http://sassdoc.com/configuration/|Sassdoc configuration}
@param {string} sourceDir - source directory
@param {Object} config - configuration object
@return {Object} json object


function dedupeArray(arr) {
  return arr.reduce(
    (p, item) => {
      const type = item.type || item.context.type;
      const name = item.name || item.context.name;
      const id = [type, name].join('|');

      if (p.temp.indexOf(id) === -1) {
        p.out.push(item);
        p.temp.push(id);
      }
      return p;
    },
    { temp: [], out: [] }
  ).out;
}

function dedupeArray ( arr ) { return arr . reduce ( ( p , item ) => { const type = item . type || item . context . type ; const name = item . name || item . context . name ; const id = [ type , name ] . join ( '|' ) ; if ( p . temp . indexOf ( id ) === - 1 ) { p . out . push ( item ) ; p . temp . push ( id ) ; } return p ; } , { temp : [ ] , out : [ ] } ) . out ; }

Remove duplicate objects in `require` and `usedBy` arrays. Array objects have
`name` and `type` properties, sometimes nested in a `context` object.
@param {Array} arr - array with potential duplicates
@return {Array} deduped array

Remove duplicate objects in require and usedBy arrays . Array objects have name and type properties sometimes nested in a context object .


async function createMarkdown(sourceDir, config) {
  config = config || {};

  return sassdoc.parse(sourceDir, config).then(
    data => {
      let markdownFile = '';

      const documentedItems = data.filter(
        (item, index) => item.access === 'public' || item.access === 'private'
      );

      markdownFile += `# Sass API

| Mark | Description |
| --- | --- |
| ✅ | Public functions, mixins, placeholders, and variables |
| ❌ | Private items - not supported outside package's build |
| ⚠ | Deprecated items - may not be available in future releases |

<!-- toc -->
<!-- tocstop -->`;

      let currentGroup = '';

      documentedItems.forEach(item => {
        const itemGroup = createGroupName(item.group);

        if (itemGroup !== currentGroup) {
          markdownFile += `\n\n## ${itemGroup}`;
          currentGroup = itemGroup;
        }

        markdownFile += createMarkdownItem(item);
      });

      return prettier.format(
        toc.insert(markdownFile, { slugify }),
        prettierOptions
      );
    },
    err => {
      console.error(err);
    }
  );
}

async function createMarkdown ( sourceDir , config ) { config = config || { } ; return sassdoc . parse ( sourceDir , config ) . then ( data => { let markdownFile = '' ; const documentedItems = data . filter ( ( item , index ) => item . access === 'public' || item . access === 'private' ) ; markdownFile += ` ` ; let currentGroup = '' ; documentedItems . forEach ( item => { const itemGroup = createGroupName ( item . group ) ; if ( itemGroup !== currentGroup ) { markdownFile += ` \n \n ${ itemGroup } ` ; currentGroup = itemGroup ; } markdownFile += createMarkdownItem ( item ) ; } ) ; return prettier . format ( toc . insert ( markdownFile , { slugify } ) , prettierOptions ) ; } , err => { console . error ( err ) ; } ) ; }

Create a markdown file of documented Sass items
@see {@link http://sassdoc.com/configuration/|Sassdoc configuration}
@param {string} sourceDir - source directory
@param {Object} config - configuration object
@return {string} markdown


function flattenOptions(options) {
  const o = {};
  // eslint-disable-next-line guard-for-in, no-restricted-syntax
  for (const key in options) {
    o[key] = options[key];
  }
  return o;
}

`this.options` create-component mix-in creates prototype chain so that `options` given in constructor argument wins over the one defined in static `options` property 'Flatpickr' wants flat structure of object instead

this . options create - component mix - in creates prototype chain so that options given in constructor argument wins over the one defined in static options property Flatpickr wants flat structure of object instead


function append(str, prefix = '') {
  const item = document.createElement('li');

  item.textContent = prefix + str;
  list.appendChild(item);
}

function append ( str , prefix = '' ) { const item = document . createElement ( 'li' ) ; item . textContent = prefix + str ; list . appendChild ( item ) ; }

Append list item

@param {*} str List item content
@param {string} prefix Prefix for global
@returns {void}


function multiresNodeSort(a, b) {
        // Base tiles are always first
        if (a.level == 1 && b.level != 1) {
            return -1;
        }
        if (b. level == 1 && a.level != 1) {
            return 1;
        }

        // Higher timestamp first
        return b.timestamp - a.timestamp;
    }

function
multiresNodeSort
(
a
,
b
)
{
// Base tiles are always first
if
(
a
.
level
==
1
&&
b
.
level
!=
1
)
{
return
1
;
}
if
(
b
.
level
==
1
&&
a
.
level
!=
1
)
{
return
1
;
}
// Higher timestamp first
return
b
.
timestamp
a
.
timestamp
;
}

Sorting method for multires nodes.
@private
@param {MultiresNode} a - First node.
@param {MultiresNode} b - Second node.
@returns {number} Base tiles first, then higher timestamp first.


function multiresNodeRenderSort(a, b) {
        // Lower zoom levels first
        if (a.level != b.level) {
            return a.level - b.level;
        }

        // Lower distance from center first
        return a.diff - b.diff;
    }

function
multiresNodeRenderSort
(
a
,
b
)
{
// Lower zoom levels first
if
(
a
.
level
!=
b
.
level
)
{
return
a
.
level
b
.
level
;
}
// Lower distance from center first
return
a
.
diff
b
.
diff
;
}

Sorting method for multires node rendering.
@private
@param {MultiresNode} a - First node.
@param {MultiresNode} b - Second node.
@returns {number} Lower zoom levels first, then closest to center first.

Sorting method for multires node rendering .


function multiresDraw() {
        if (!program.drawInProgress) {
            program.drawInProgress = true;
            gl.clear(gl.COLOR_BUFFER_BIT);
            for ( var i = 0; i < program.currentNodes.length; i++ ) {
                if (program.currentNodes[i].textureLoaded > 1) {
                    //var color = program.currentNodes[i].color;
                    //gl.uniform4f(program.colorUniform, color[0], color[1], color[2], 1.0);

                    // Bind vertex buffer and pass vertices to WebGL
                    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertBuf);
                    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(program.currentNodes[i].vertices), gl.STATIC_DRAW);
                    gl.vertexAttribPointer(program.vertPosLocation, 3, gl.FLOAT, false, 0, 0);

                    // Prep for texture
                    gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertTexCoordBuf);
                    gl.vertexAttribPointer(program.texCoordLocation, 2, gl.FLOAT, false, 0, 0);

                    // Bind texture and draw tile
                    gl.bindTexture(gl.TEXTURE_2D, program.currentNodes[i].texture); // Bind program.currentNodes[i].texture to TEXTURE0
                    gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
                }
            }
            program.drawInProgress = false;
        }
    }


function MultiresNode(vertices, side, level, x, y, path) {
        this.vertices = vertices;
        this.side = side;
        this.level = level;
        this.x = x;
        this.y = y;
        this.path = path.replace('%s',side).replace('%l',level).replace('%x',x).replace('%y',y);
    }

function MultiresNode ( vertices , side , level , x , y , path ) { this . vertices = vertices ; this . side = side ; this . level = level ; this . x = x ; this . y = y ; this . path = path . replace ( '%s' , side ) . replace ( '%l' , level ) . replace ( '%x' , x ) . replace ( '%y' , y ) ; }

Creates new multires node.
@constructor
@private
@param {number[]} vertices - Node's verticies.
@param {string} side - Node's cube face.
@param {number} level - Node's zoom level.
@param {number} x - Node's x position.
@param {number} y - Node's y position.
@param {string} path - Node's path.


Rotates a 3x3 matrix.
@private
@param {number[]} m - Matrix to rotate.
@param {number[]} angle - Angle to rotate by in radians.
@param {string} axis - Axis to rotate about (`x`, `y`, or `z`).
@returns {number[]} Rotated matrix.


Turns a 3x3 matrix into a 4x4 matrix.
@private
@param {number[]} m - Input matrix.
@returns {number[]} Expanded matrix.


function makePersp(hfov, aspect, znear, zfar) {
        var fovy = 2 * Math.atan(Math.tan(hfov/2) * gl.drawingBufferHeight / gl.drawingBufferWidth);
        var f = 1 / Math.tan(fovy/2);
        return [
            f/aspect,   0,  0,  0,
                   0,   f,  0,  0,
                   0,   0,  (zfar+znear)/(znear-zfar), (2*zfar*znear)/(znear-zfar),
                   0,   0, -1,  0
        ];
    }

function makePersp ( hfov , aspect , znear , zfar ) { var fovy = 2 * Math . atan ( Math . tan ( hfov / 2 ) * gl . drawingBufferHeight / gl . drawingBufferWidth ) ; var f = 1 / Math . tan ( fovy / 2 ) ; return [ f / aspect , 0 , 0 , 0 , 0 , f , 0 , 0 , 0 , 0 , ( zfar + znear ) / ( znear - zfar ) , ( 2 * zfar * znear ) / ( znear - zfar ) , 0 , 0 , - 1 , 0 ] ; }

Creates a perspective matrix.
@private
@param {number} hfov - Desired horizontal field of view.
@param {number} aspect - Desired aspect ratio.
@param {number} znear - Near distance.
@param {number} zfar - Far distance.
@returns {number[]} Generated perspective matrix.


function processLoadedTexture(img, tex) {
        gl.bindTexture(gl.TEXTURE_2D, tex);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        gl.bindTexture(gl.TEXTURE_2D, null);
    }

function processLoadedTexture ( img , tex ) { gl . bindTexture ( gl . TEXTURE_2D , tex ) ; gl . texImage2D ( gl . TEXTURE_2D , 0 , gl . RGB , gl . RGB , gl . UNSIGNED_BYTE , img ) ; gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MAG_FILTER , gl . LINEAR ) ; gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_MIN_FILTER , gl . LINEAR ) ; gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_S , gl . CLAMP_TO_EDGE ) ; gl . texParameteri ( gl . TEXTURE_2D , gl . TEXTURE_WRAP_T , gl . CLAMP_TO_EDGE ) ; gl . bindTexture ( gl . TEXTURE_2D , null ) ; }

Processes a loaded texture image into a WebGL texture.
@private
@param {Image} img - Input image.
@param {WebGLTexture} tex - Texture to bind image to.

Processes a loaded texture image into a WebGL texture .


function checkZoom(hfov) {
        // Find optimal level
        var newLevel = 1;
        while ( newLevel < image.maxLevel &&
            gl.drawingBufferWidth > image.tileResolution *
            Math.pow(2, newLevel - 1) * Math.tan(hfov / 2) * 0.707 ) {
            newLevel++;
        }

        // Apply change
        program.level = newLevel;
    }

function
checkZoom
(
hfov
)
{
// Find optimal level
var
newLevel
=
1
;
while
(
newLevel
<
image
.
maxLevel
&&
gl
.
drawingBufferWidth
>
image
.
tileResolution
*
Math
.
pow
(
2
,
newLevel
1
)
*
Math
.
tan
(
hfov
/
2
)
*
0.707
)
{
newLevel
++
;
}
// Apply change
program
.
level
=
newLevel
;
}

Finds and applies optimal multires zoom level.
@private
@param {number} hfov - Horizontal field of view to check at.

Finds and applies optimal multires zoom level .


Rotates perspective matrix.
@private
@param {number[]} p - Perspective matrix.
@param {number[]} r - Rotation matrix.
@returns {number[]} Rotated matrix.


function checkInView(m, v) {
        var vpp = applyRotPerspToVec(m, v);
        var winX = vpp[0]*vpp[3];
        var winY = vpp[1]*vpp[3];
        var winZ = vpp[2]*vpp[3];
        var ret = [0, 0, 0];

        if ( winX < -1 )
            ret[0] = -1;
        if ( winX > 1 )
            ret[0] = 1;
        if ( winY < -1 )
            ret[1] = -1;
        if ( winY > 1 )
            ret[1] = 1;
        if ( winZ < -1 || winZ > 1 )
            ret[2] = 1;
        return ret;
    }

function checkInView ( m , v ) { var vpp = applyRotPerspToVec ( m , v ) ; var winX = vpp [ 0 ] * vpp [ 3 ] ; var winY = vpp [ 1 ] * vpp [ 3 ] ; var winZ = vpp [ 2 ] * vpp [ 3 ] ; var ret = [ 0 , 0 , 0 ] ; if ( winX < - 1 ) ret [ 0 ] = - 1 ; if ( winX > 1 ) ret [ 0 ] = 1 ; if ( winY < - 1 ) ret [ 1 ] = - 1 ; if ( winY > 1 ) ret [ 1 ] = 1 ; if ( winZ < - 1 || winZ > 1 ) ret [ 2 ] = 1 ; return ret ; }

Checks if a vertex is visible.
@private
@param {number[]} m - Rotated perspective matrix.
@param {number[]} v - Input vertex.
@returns {number} 1 or -1 if the vertex is or is not visible,
respectively.


function onImageLoad() {
    if (!renderer)
        renderer = new libpannellum.renderer(renderContainer);

    // Only add event listeners once
    if (!listenersAdded) {
        listenersAdded = true;
        dragFix.addEventListener('mousedown', onDocumentMouseDown, false);
        document.addEventListener('mousemove', onDocumentMouseMove, false);
        document.addEventListener('mouseup', onDocumentMouseUp, false);
        if (config.mouseZoom) {
            uiContainer.addEventListener('mousewheel', onDocumentMouseWheel, false);
            uiContainer.addEventListener('DOMMouseScroll', onDocumentMouseWheel, false);
        }
        if (config.doubleClickZoom) {
            dragFix.addEventListener('dblclick', onDocumentDoubleClick, false);
        }
        container.addEventListener('mozfullscreenchange', onFullScreenChange, false);
        container.addEventListener('webkitfullscreenchange', onFullScreenChange, false);
        container.addEventListener('msfullscreenchange', onFullScreenChange, false);
        container.addEventListener('fullscreenchange', onFullScreenChange, false);
        window.addEventListener('resize', onDocumentResize, false);
        window.addEventListener('orientationchange', onDocumentResize, false);
        if (!config.disableKeyboardCtrl) {
            container.addEventListener('keydown', onDocumentKeyPress, false);
            container.addEventListener('keyup', onDocumentKeyUp, false);
            container.addEventListener('blur', clearKeys, false);
        }
        document.addEventListener('mouseleave', onDocumentMouseUp, false);
        if (document.documentElement.style.pointerAction === '' &&
            document.documentElement.style.touchAction === '') {
            dragFix.addEventListener('pointerdown', onDocumentPointerDown, false);
            dragFix.addEventListener('pointermove', onDocumentPointerMove, false);
            dragFix.addEventListener('pointerup', onDocumentPointerUp, false);
            dragFix.addEventListener('pointerleave', onDocumentPointerUp, false);
        } else {
            dragFix.addEventListener('touchstart', onDocumentTouchStart, false);
            dragFix.addEventListener('touchmove', onDocumentTouchMove, false);
            dragFix.addEventListener('touchend', onDocumentTouchEnd, false);
        }

        // Deal with MS pointer events
        if (window.navigator.pointerEnabled)
            container.style.touchAction = 'none';
    }

    renderInit();
    setHfov(config.hfov); // possibly adapt hfov after configuration and canvas is complete; prevents empty space on top or bottom by zomming out too much
    setTimeout(function(){isTimedOut = true;}, 500);
}

Create renderer and initialize event listeners once image is loaded.
@private

Create renderer and initialize event listeners once image is loaded .


function(tag) {
                var result;
                if (xmpData.indexOf(tag + '="') >= 0) {
                    result = xmpData.substring(xmpData.indexOf(tag + '="') + tag.length + 2);
                    result = result.substring(0, result.indexOf('"'));
                } else if (xmpData.indexOf(tag + '>') >= 0) {
                    result = xmpData.substring(xmpData.indexOf(tag + '>') + tag.length + 1);
                    result = result.substring(0, result.indexOf('<'));
                }
                if (result !== undefined) {
                    return Number(result);
                }
                return null;
            }

function ( tag ) { var result ; if ( xmpData . indexOf ( tag + '="' ) >= 0 ) { result = xmpData . substring ( xmpData . indexOf ( tag + '="' ) + tag . length + 2 ) ; result = result . substring ( 0 , result . indexOf ( '"' ) ) ; } else if ( xmpData . indexOf ( tag + '>' ) >= 0 ) { result = xmpData . substring ( xmpData . indexOf ( tag + '>' ) + tag . length + 1 ) ; result = result . substring ( 0 , result . indexOf ( '<' ) ) ; } if ( result !== undefined ) { return Number ( result ) ; } return null ; }

Extract the requested tag from the XMP data


function anError(errorMsg) {
    if (errorMsg === undefined)
        errorMsg = config.strings.genericWebGLError;
    infoDisplay.errorMsg.innerHTML = '<p>' + errorMsg + '</p>';
    controls.load.style.display = 'none';
    infoDisplay.load.box.style.display = 'none';
    infoDisplay.errorMsg.style.display = 'table';
    error = true;
    renderContainer.style.display = 'none';
    fireEvent('error', errorMsg);
}

function anError ( errorMsg ) { if ( errorMsg === undefined ) errorMsg = config . strings . genericWebGLError ; infoDisplay . errorMsg . innerHTML = '<p>' + errorMsg + '</p>' ; controls . load . style . display = 'none' ; infoDisplay . load . box . style . display = 'none' ; infoDisplay . errorMsg . style . display = 'table' ; error = true ; renderContainer . style . display = 'none' ; fireEvent ( 'error' , errorMsg ) ; }

Displays an error message.
@private
@param {string} errorMsg - Error message to display. If not specified, a
generic WebGL error is displayed.


function clearError() {
    if (error) {
        infoDisplay.load.box.style.display = 'none';
        infoDisplay.errorMsg.style.display = 'none';
        error = false;
        fireEvent('errorcleared');
    }
}

function clearError ( ) { if ( error ) { infoDisplay . load . box . style . display = 'none' ; infoDisplay . errorMsg . style . display = 'none' ; error = false ; fireEvent ( 'errorcleared' ) ; } }


function aboutMessage(event) {
    var pos = mousePosition(event);
    aboutMsg.style.left = pos.x + 'px';
    aboutMsg.style.top = pos.y + 'px';
    clearTimeout(aboutMessage.t1);
    clearTimeout(aboutMessage.t2);
    aboutMsg.style.display = 'block';
    aboutMsg.style.opacity = 1;
    aboutMessage.t1 = setTimeout(function() {aboutMsg.style.opacity = 0;}, 2000);
    aboutMessage.t2 = setTimeout(function() {aboutMsg.style.display = 'none';}, 2500);
    event.preventDefault();
}

function aboutMessage ( event ) { var pos = mousePosition ( event ) ; aboutMsg . style . left = pos . x + 'px' ; aboutMsg . style . top = pos . y + 'px' ; clearTimeout ( aboutMessage . t1 ) ; clearTimeout ( aboutMessage . t2 ) ; aboutMsg . style . display = 'block' ; aboutMsg . style . opacity = 1 ; aboutMessage . t1 = setTimeout ( function ( ) { aboutMsg . style . opacity = 0 ; } , 2000 ) ; aboutMessage . t2 = setTimeout ( function ( ) { aboutMsg . style . display = 'none' ; } , 2500 ) ; event . preventDefault ( ) ; }

Displays about message.
@private
@param {MouseEvent} event - Right click location


function mousePosition(event) {
    var bounds = container.getBoundingClientRect();
    var pos = {};
    // pageX / pageY needed for iOS
    pos.x = (event.clientX || event.pageX) - bounds.left;
    pos.y = (event.clientY || event.pageY) - bounds.top;
    return pos;
}

function
mousePosition
(
event
)
{
var
bounds
=
container
.
getBoundingClientRect
(
)
;
var
pos
=
{
}
;
// pageX / pageY needed for iOS
pos
.
x
=
(
event
.
clientX
||
event
.
pageX
)
bounds
.
left
;
pos
.
y
=
(
event
.
clientY
||
event
.
pageY
)
bounds
.
top
;
return
pos
;
}

Calculate mouse position relative to top left of viewer container.
@private
@param {MouseEvent} event - Mouse event to use in calculation
@returns {Object} Calculated X and Y coordinates

Calculate mouse position relative to top left of viewer container .


function onDocumentMouseDown(event) {
    // Override default action
    event.preventDefault();
    // But not all of it
    container.focus();

    // Only do something if the panorama is loaded
    if (!loaded || !config.draggable) {
        return;
    }

    // Calculate mouse position relative to top left of viewer container
    var pos = mousePosition(event);

    // Log pitch / yaw of mouse click when debugging / placing hot spots
    if (config.hotSpotDebug) {
        var coords = mouseEventToCoords(event);
        console.log('Pitch: ' + coords[0] + ', Yaw: ' + coords[1] + ', Center Pitch: ' +
            config.pitch + ', Center Yaw: ' + config.yaw + ', HFOV: ' + config.hfov);
    }

    // Turn off auto-rotation if enabled
    stopAnimation();

    stopOrientation();
    config.roll = 0;

    speed.hfov = 0;

    isUserInteracting = true;
    latestInteraction = Date.now();

    onPointerDownPointerX = pos.x;
    onPointerDownPointerY = pos.y;

    onPointerDownYaw = config.yaw;
    onPointerDownPitch = config.pitch;

    uiContainer.classList.add('pnlm-grabbing');
    uiContainer.classList.remove('pnlm-grab');

    fireEvent('mousedown', event);
    animateInit();
}

Event handler for mouse clicks. Initializes panning. Prints center and click
location coordinates when hot spot debugging is enabled.
@private
@param {MouseEvent} event - Document mouse down event.

Event handler for mouse clicks . Initializes panning . Prints center and click location coordinates when hot spot debugging is enabled .


function onDocumentDoubleClick(event) {
    if (config.minHfov === config.hfov) {
        _this.setHfov(origHfov, 1000);
    } else {
        var coords = mouseEventToCoords(event);
        _this.lookAt(coords[0], coords[1], config.minHfov, 1000);
    }
}

function onDocumentDoubleClick ( event ) { if ( config . minHfov === config . hfov ) { _this . setHfov ( origHfov , 1000 ) ; } else { var coords = mouseEventToCoords ( event ) ; _this . lookAt ( coords [ 0 ] , coords [ 1 ] , config . minHfov , 1000 ) ; } }

Event handler for double clicks. Zooms in at clicked location
@private
@param {MouseEvent} event - Document mouse down event.

Event handler for double clicks . Zooms in at clicked location


function mouseEventToCoords(event) {
    var pos = mousePosition(event);
    var canvas = renderer.getCanvas();
    var canvasWidth = canvas.clientWidth,
        canvasHeight = canvas.clientHeight;
    var x = pos.x / canvasWidth * 2 - 1;
    var y = (1 - pos.y / canvasHeight * 2) * canvasHeight / canvasWidth;
    var focal = 1 / Math.tan(config.hfov * Math.PI / 360);
    var s = Math.sin(config.pitch * Math.PI / 180);
    var c = Math.cos(config.pitch * Math.PI / 180);
    var a = focal * c - y * s;
    var root = Math.sqrt(x*x + a*a);
    var pitch = Math.atan((y * c + focal * s) / root) * 180 / Math.PI;
    var yaw = Math.atan2(x / root, a / root) * 180 / Math.PI + config.yaw;
    if (yaw < -180)
        yaw += 360;
    if (yaw > 180)
        yaw -= 360;
    return [pitch, yaw];
}

function mouseEventToCoords ( event ) { var pos = mousePosition ( event ) ; var canvas = renderer . getCanvas ( ) ; var canvasWidth = canvas . clientWidth , canvasHeight = canvas . clientHeight ; var x = pos . x / canvasWidth * 2 - 1 ; var y = ( 1 - pos . y / canvasHeight * 2 ) * canvasHeight / canvasWidth ; var focal = 1 / Math . tan ( config . hfov * Math . PI / 360 ) ; var s = Math . sin ( config . pitch * Math . PI / 180 ) ; var c = Math . cos ( config . pitch * Math . PI / 180 ) ; var a = focal * c - y * s ; var root = Math . sqrt ( x * x + a * a ) ; var pitch = Math . atan ( ( y * c + focal * s ) / root ) * 180 / Math . PI ; var yaw = Math . atan2 ( x / root , a / root ) * 180 / Math . PI + config . yaw ; if ( yaw < - 180 ) yaw += 360 ; if ( yaw > 180 ) yaw -= 360 ; return [ pitch , yaw ] ; }

Calculate panorama pitch and yaw from location of mouse event.
@private
@param {MouseEvent} event - Document mouse down event.
@returns {number[]} [pitch, yaw]

Calculate panorama pitch and yaw from location of mouse event .


function onDocumentMouseMove(event) {
    if (isUserInteracting && loaded) {
        latestInteraction = Date.now();
        var canvas = renderer.getCanvas();
        var canvasWidth = canvas.clientWidth,
            canvasHeight = canvas.clientHeight;
        var pos = mousePosition(event);
        //TODO: This still isn't quite right
        var yaw = ((Math.atan(onPointerDownPointerX / canvasWidth * 2 - 1) - Math.atan(pos.x / canvasWidth * 2 - 1)) * 180 / Math.PI * config.hfov / 90) + onPointerDownYaw;
        speed.yaw = (yaw - config.yaw) % 360 * 0.2;
        config.yaw = yaw;

        var vfov = 2 * Math.atan(Math.tan(config.hfov/360*Math.PI) * canvasHeight / canvasWidth) * 180 / Math.PI;

        var pitch = ((Math.atan(pos.y / canvasHeight * 2 - 1) - Math.atan(onPointerDownPointerY / canvasHeight * 2 - 1)) * 180 / Math.PI * vfov / 90) + onPointerDownPitch;
        speed.pitch = (pitch - config.pitch) * 0.2;
        config.pitch = pitch;
    }
}

function
onDocumentMouseMove
(
event
)
{
if
(
isUserInteracting
&&
loaded
)
{
latestInteraction
=
Date
.
now
(
)
;
var
canvas
=
renderer
.
getCanvas
(
)
;
var
canvasWidth
=
canvas
.
clientWidth
,
canvasHeight
=
canvas
.
clientHeight
;
var
pos
=
mousePosition
(
event
)
;
//TODO: This still isn't quite right
var
yaw
=
(
(
Math
.
atan
(
onPointerDownPointerX
/
canvasWidth
*
2
1
)
Math
.
atan
(
pos
.
x
/
canvasWidth
*
2
1
)
)
*
180
/
Math
.
PI
*
config
.
hfov
/
90
)
+
onPointerDownYaw
;
speed
.
yaw
=
(
yaw
config
.
yaw
)
%
360
*
0.2
;
config
.
yaw
=
yaw
;
var
vfov
=
2
*
Math
.
atan
(
Math
.
tan
(
config
.
hfov
/
360
*
Math
.
PI
)
*
canvasHeight
/
canvasWidth
)
*
180
/
Math
.
PI
;
var
pitch
=
(
(
Math
.
atan
(
pos
.
y
/
canvasHeight
*
2
1
)
Math
.
atan
(
onPointerDownPointerY
/
canvasHeight
*
2
1
)
)
*
180
/
Math
.
PI
*
vfov
/
90
)
+
onPointerDownPitch
;
speed
.
pitch
=
(
pitch
config
.
pitch
)
*
0.2
;
config
.
pitch
=
pitch
;
}
}

Event handler for mouse moves. Pans center of view.
@private
@param {MouseEvent} event - Document mouse move event.

Event handler for mouse moves . Pans center of view .


function onDocumentMouseUp(event) {
    if (!isUserInteracting) {
        return;
    }
    isUserInteracting = false;
    if (Date.now() - latestInteraction > 15) {
        // Prevents jump when user rapidly moves mouse, stops, and then
        // releases the mouse button
        speed.pitch = speed.yaw = 0;
    }
    uiContainer.classList.add('pnlm-grab');
    uiContainer.classList.remove('pnlm-grabbing');
    latestInteraction = Date.now();

    fireEvent('mouseup', event);
}

Event handler for mouse up events. Stops panning.
@private

Event handler for mouse up events . Stops panning .


function onDocumentTouchStart(event) {
    // Only do something if the panorama is loaded
    if (!loaded || !config.draggable) {
        return;
    }

    // Turn off auto-rotation if enabled
    stopAnimation();

    stopOrientation();
    config.roll = 0;

    speed.hfov = 0;

    // Calculate touch position relative to top left of viewer container
    var pos0 = mousePosition(event.targetTouches[0]);

    onPointerDownPointerX = pos0.x;
    onPointerDownPointerY = pos0.y;

    if (event.targetTouches.length == 2) {
        // Down pointer is the center of the two fingers
        var pos1 = mousePosition(event.targetTouches[1]);
        onPointerDownPointerX += (pos1.x - pos0.x) * 0.5;
        onPointerDownPointerY += (pos1.y - pos0.y) * 0.5;
        onPointerDownPointerDist = Math.sqrt((pos0.x - pos1.x) * (pos0.x - pos1.x) +
                                             (pos0.y - pos1.y) * (pos0.y - pos1.y));
    }
    isUserInteracting = true;
    latestInteraction = Date.now();

    onPointerDownYaw = config.yaw;
    onPointerDownPitch = config.pitch;

    fireEvent('touchstart', event);
    animateInit();
}

Event handler for touches. Initializes panning if one touch or zooming if
two touches.
@private
@param {TouchEvent} event - Document touch start event.

Event handler for touches . Initializes panning if one touch or zooming if two touches .


function onDocumentTouchMove(event) {
    if (!config.draggable) {
        return;
    }

    // Override default action
    event.preventDefault();
    if (loaded) {
        latestInteraction = Date.now();
    }
    if (isUserInteracting && loaded) {
        var pos0 = mousePosition(event.targetTouches[0]);
        var clientX = pos0.x;
        var clientY = pos0.y;

        if (event.targetTouches.length == 2 && onPointerDownPointerDist != -1) {
            var pos1 = mousePosition(event.targetTouches[1]);
            clientX += (pos1.x - pos0.x) * 0.5;
            clientY += (pos1.y - pos0.y) * 0.5;
            var clientDist = Math.sqrt((pos0.x - pos1.x) * (pos0.x - pos1.x) +
                                       (pos0.y - pos1.y) * (pos0.y - pos1.y));
            setHfov(config.hfov + (onPointerDownPointerDist - clientDist) * 0.1);
            onPointerDownPointerDist = clientDist;
        }

        // The smaller the config.hfov value (the more zoomed-in the user is), the faster
        // yaw/pitch are perceived to change on one-finger touchmove (panning) events and vice versa.
        // To improve usability at both small and large zoom levels (config.hfov values)
        // we introduce a dynamic pan speed coefficient.
        //
        // Currently this seems to *roughly* keep initial drag/pan start position close to
        // the user's finger while panning regardless of zoom level / config.hfov value.
        var touchmovePanSpeedCoeff = (config.hfov / 360) * config.touchPanSpeedCoeffFactor;

        var yaw = (onPointerDownPointerX - clientX) * touchmovePanSpeedCoeff + onPointerDownYaw;
        speed.yaw = (yaw - config.yaw) % 360 * 0.2;
        config.yaw = yaw;

        var pitch = (clientY - onPointerDownPointerY) * touchmovePanSpeedCoeff + onPointerDownPitch;
        speed.pitch = (pitch - config.pitch) * 0.2;
        config.pitch = pitch;
    }
}

Event handler for touch movements. Pans center of view if one touch or
adjusts zoom if two touches.
@private
@param {TouchEvent} event - Document touch move event.

Event handler for touch movements . Pans center of view if one touch or adjusts zoom if two touches .


function onDocumentMouseWheel(event) {
    // Only do something if the panorama is loaded and mouse wheel zoom is enabled
    if (!loaded || (config.mouseZoom == 'fullscreenonly' && !fullscreenActive)) {
        return;
    }

    event.preventDefault();

    // Turn off auto-rotation if enabled
    stopAnimation();
    latestInteraction = Date.now();

    if (event.wheelDeltaY) {
        // WebKit
        setHfov(config.hfov - event.wheelDeltaY * 0.05);
        speed.hfov = event.wheelDelta < 0 ? 1 : -1;
    } else if (event.wheelDelta) {
        // Opera / Explorer 9
        setHfov(config.hfov - event.wheelDelta * 0.05);
        speed.hfov = event.wheelDelta < 0 ? 1 : -1;
    } else if (event.detail) {
        // Firefox
        setHfov(config.hfov + event.detail * 1.5);
        speed.hfov = event.detail > 0 ? 1 : -1;
    }
    animateInit();
}

Event handler for mouse wheel. Changes zoom.
@private
@param {WheelEvent} event - Document mouse wheel event.

Event handler for mouse wheel . Changes zoom .


function onDocumentKeyPress(event) {
    // Turn off auto-rotation if enabled
    stopAnimation();
    latestInteraction = Date.now();

    stopOrientation();
    config.roll = 0;

    // Record key pressed
    var keynumber = event.which || event.keycode;

    // Override default action for keys that are used
    if (config.capturedKeyNumbers.indexOf(keynumber) < 0)
        return;
    event.preventDefault();

    // If escape key is pressed
    if (keynumber == 27) {
        // If in fullscreen mode
        if (fullscreenActive) {
            toggleFullscreen();
        }
    } else {
        // Change key
        changeKey(keynumber, true);
    }
}

Event handler for key presses. Updates list of currently pressed keys.
@private
@param {KeyboardEvent} event - Document key press event.

Event handler for key presses . Updates list of currently pressed keys .


function onDocumentKeyUp(event) {
    // Record key pressed
    var keynumber = event.which || event.keycode;

    // Override default action for keys that are used
    if (config.capturedKeyNumbers.indexOf(keynumber) < 0)
        return;
    event.preventDefault();

    // Change key
    changeKey(keynumber, false);
}

Event handler for key releases. Updates list of currently pressed keys.
@private
@param {KeyboardEvent} event - Document key up event.

Event handler for key releases . Updates list of currently pressed keys .


function changeKey(keynumber, value) {
    var keyChanged = false;
    switch(keynumber) {
        // If minus key is released
        case 109: case 189: case 17: case 173:
            if (keysDown[0] != value) { keyChanged = true; }
            keysDown[0] = value; break;

        // If plus key is released
        case 107: case 187: case 16: case 61:
            if (keysDown[1] != value) { keyChanged = true; }
            keysDown[1] = value; break;

        // If up arrow is released
        case 38:
            if (keysDown[2] != value) { keyChanged = true; }
            keysDown[2] = value; break;

        // If "w" is released
        case 87:
            if (keysDown[6] != value) { keyChanged = true; }
            keysDown[6] = value; break;

        // If down arrow is released
        case 40:
            if (keysDown[3] != value) { keyChanged = true; }
            keysDown[3] = value; break;

        // If "s" is released
        case 83:
            if (keysDown[7] != value) { keyChanged = true; }
            keysDown[7] = value; break;

        // If left arrow is released
        case 37:
            if (keysDown[4] != value) { keyChanged = true; }
            keysDown[4] = value; break;

        // If "a" is released
        case 65:
            if (keysDown[8] != value) { keyChanged = true; }
            keysDown[8] = value; break;

        // If right arrow is released
        case 39:
            if (keysDown[5] != value) { keyChanged = true; }
            keysDown[5] = value; break;

        // If "d" is released
        case 68:
            if (keysDown[9] != value) { keyChanged = true; }
            keysDown[9] = value;
    }

    if (keyChanged && value) {
        if (typeof performance !== 'undefined' && performance.now()) {
            prevTime = performance.now();
        } else {
            prevTime = Date.now();
        }
        animateInit();
    }
}

function
changeKey
(
keynumber
,
value
)
{
var
keyChanged
=
false
;
switch
(
keynumber
)
{
// If minus key is released
case
109
:
case
189
:
case
17
:
case
173
:
if
(
keysDown
[
0
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
0
]
=
value
;
break
;
// If plus key is released
case
107
:
case
187
:
case
16
:
case
61
:
if
(
keysDown
[
1
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
1
]
=
value
;
break
;
// If up arrow is released
case
38
:
if
(
keysDown
[
2
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
2
]
=
value
;
break
;
// If "w" is released
case
87
:
if
(
keysDown
[
6
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
6
]
=
value
;
break
;
// If down arrow is released
case
40
:
if
(
keysDown
[
3
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
3
]
=
value
;
break
;
// If "s" is released
case
83
:
if
(
keysDown
[
7
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
7
]
=
value
;
break
;
// If left arrow is released
case
37
:
if
(
keysDown
[
4
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
4
]
=
value
;
break
;
// If "a" is released
case
65
:
if
(
keysDown
[
8
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
8
]
=
value
;
break
;
// If right arrow is released
case
39
:
if
(
keysDown
[
5
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
5
]
=
value
;
break
;
// If "d" is released
case
68
:
if
(
keysDown
[
9
]
!=
value
)
{
keyChanged
=
true
;
}
keysDown
[
9
]
=
value
;
}
if
(
keyChanged
&&
value
)
{
if
(
typeof
performance
!==
'undefined'
&&
performance
.
now
(
)
)
{
prevTime
=
performance
.
now
(
)
;
}
else
{
prevTime
=
Date
.
now
(
)
;
}
animateInit
(
)
;
}
}

Updates list of currently pressed keys.
@private
@param {number} keynumber - Key number.
@param {boolean} value - Whether or not key is pressed.

Updates list of currently pressed keys .


function animateMove(axis) {
    var t = animatedMove[axis];
    var normTime = Math.min(1, Math.max((Date.now() - t.startTime) / 1000 / (t.duration / 1000), 0));
    var result = t.startPosition + config.animationTimingFunction(normTime) * (t.endPosition - t.startPosition);
    if ((t.endPosition > t.startPosition && result >= t.endPosition) ||
        (t.endPosition < t.startPosition && result <= t.endPosition) ||
        t.endPosition === t.startPosition) {
        result = t.endPosition;
        speed[axis] = 0;
        delete animatedMove[axis];
    }
    config[axis] = result;
}

function animateMove ( axis ) { var t = animatedMove [ axis ] ; var normTime = Math . min ( 1 , Math . max ( ( Date . now ( ) - t . startTime ) / 1000 / ( t . duration / 1000 ) , 0 ) ) ; var result = t . startPosition + config . animationTimingFunction ( normTime ) * ( t . endPosition - t . startPosition ) ; if ( ( t . endPosition > t . startPosition && result >= t . endPosition ) || ( t . endPosition < t . startPosition && result <= t . endPosition ) || t . endPosition === t . startPosition ) { result = t . endPosition ; speed [ axis ] = 0 ; delete animatedMove [ axis ] ; } config [ axis ] = result ; }

Animates moves.
@param {string} axis - Axis to animate
@private


function animate() {
    render();
    if (autoRotateStart)
        clearTimeout(autoRotateStart);
    if (isUserInteracting || orientation === true) {
        requestAnimationFrame(animate);
    } else if (keysDown[0] || keysDown[1] || keysDown[2] || keysDown[3] ||
        keysDown[4] || keysDown[5] || keysDown[6] || keysDown[7] ||
        keysDown[8] || keysDown[9] || config.autoRotate ||
        animatedMove.pitch || animatedMove.yaw || animatedMove.hfov ||
        Math.abs(speed.yaw) > 0.01 || Math.abs(speed.pitch) > 0.01 ||
        Math.abs(speed.hfov) > 0.01) {

        keyRepeat();
        if (config.autoRotateInactivityDelay >= 0 && autoRotateSpeed &&
            Date.now() - latestInteraction > config.autoRotateInactivityDelay &&
            !config.autoRotate) {
            config.autoRotate = autoRotateSpeed;
            _this.lookAt(origPitch, undefined, origHfov, 3000);
        }
        requestAnimationFrame(animate);
    } else if (renderer && (renderer.isLoading() || (config.dynamic === true && update))) {
        requestAnimationFrame(animate);
    } else {
        fireEvent('animatefinished', {pitch: _this.getPitch(), yaw: _this.getYaw(), hfov: _this.getHfov()});
        animating = false;
        prevTime = undefined;
        var autoRotateStartTime = config.autoRotateInactivityDelay -
            (Date.now() - latestInteraction);
        if (autoRotateStartTime > 0) {
            autoRotateStart = setTimeout(function() {
                config.autoRotate = autoRotateSpeed;
                _this.lookAt(origPitch, undefined, origHfov, 3000);
                animateInit();
            }, autoRotateStartTime);
        } else if (config.autoRotateInactivityDelay >= 0 && autoRotateSpeed) {
            config.autoRotate = autoRotateSpeed;
            _this.lookAt(origPitch, undefined, origHfov, 3000);
            animateInit();
        }
    }
}

function animate ( ) { render ( ) ; if ( autoRotateStart ) clearTimeout ( autoRotateStart ) ; if ( isUserInteracting || orientation === true ) { requestAnimationFrame ( animate ) ; } else if ( keysDown [ 0 ] || keysDown [ 1 ] || keysDown [ 2 ] || keysDown [ 3 ] || keysDown [ 4 ] || keysDown [ 5 ] || keysDown [ 6 ] || keysDown [ 7 ] || keysDown [ 8 ] || keysDown [ 9 ] || config . autoRotate || animatedMove . pitch || animatedMove . yaw || animatedMove . hfov || Math . abs ( speed . yaw ) > 0.01 || Math . abs ( speed . pitch ) > 0.01 || Math . abs ( speed . hfov ) > 0.01 ) { keyRepeat ( ) ; if ( config . autoRotateInactivityDelay >= 0 && autoRotateSpeed && Date . now ( ) - latestInteraction > config . autoRotateInactivityDelay && ! config . autoRotate ) { config . autoRotate = autoRotateSpeed ; _this . lookAt ( origPitch , undefined , origHfov , 3000 ) ; } requestAnimationFrame ( animate ) ; } else if ( renderer && ( renderer . isLoading ( ) || ( config . dynamic === true && update ) ) ) { requestAnimationFrame ( animate ) ; } else { fireEvent ( 'animatefinished' , { pitch : _this . getPitch ( ) , yaw : _this . getYaw ( ) , hfov : _this . getHfov ( ) } ) ; animating = false ; prevTime = undefined ; var autoRotateStartTime = config . autoRotateInactivityDelay - ( Date . now ( ) - latestInteraction ) ; if ( autoRotateStartTime > 0 ) { autoRotateStart = setTimeout ( function ( ) { config . autoRotate = autoRotateSpeed ; _this . lookAt ( origPitch , undefined , origHfov , 3000 ) ; animateInit ( ) ; } , autoRotateStartTime ) ; } else if ( config . autoRotateInactivityDelay >= 0 && autoRotateSpeed ) { config . autoRotate = autoRotateSpeed ; _this . lookAt ( origPitch , undefined , origHfov , 3000 ) ; animateInit ( ) ; } } }

Animates view, using requestAnimationFrame to trigger rendering.
@private

Animates view using requestAnimationFrame to trigger rendering .


Converts device orientation API Tait-Bryan angles to a quaternion.
@private
@param {Number} alpha - Alpha angle (in degrees)
@param {Number} beta - Beta angle (in degrees)
@param {Number} gamma - Gamma angle (in degrees)
@returns {Quaternion} Orientation quaternion

Converts device orientation API Tait - Bryan angles to a quaternion .


function computeQuaternion(alpha, beta, gamma) {
    // Convert Tait-Bryan angles to quaternion
    var quaternion = taitBryanToQuaternion(alpha, beta, gamma);
    // Apply world transform
    quaternion = quaternion.multiply(new Quaternion(Math.sqrt(0.5), -Math.sqrt(0.5), 0, 0));
    // Apply screen transform
    var angle = window.orientation ? -window.orientation * Math.PI / 180 / 2 : 0;
    return quaternion.multiply(new Quaternion(Math.cos(angle), 0, -Math.sin(angle), 0));
}

Computes current device orientation quaternion from device orientation API
Tait-Bryan angles.
@private
@param {Number} alpha - Alpha angle (in degrees)
@param {Number} beta - Beta angle (in degrees)
@param {Number} gamma - Gamma angle (in degrees)
@returns {Quaternion} Orientation quaternion

Computes current device orientation quaternion from device orientation API Tait - Bryan angles .


function orientationListener(e) {
    var q = computeQuaternion(e.alpha, e.beta, e.gamma).toEulerAngles();
    if (typeof(orientation) == 'number' && orientation < 10) {
        // This kludge is necessary because iOS sometimes provides a few stale
        // device orientation events when the listener is removed and then
        // readded. Thus, we skip the first 10 events to prevent this from
        // causing problems.
        orientation += 1;
    } else if (orientation === 10) {
        // Record starting yaw to prevent jumping
        orientationYawOffset = q[2] / Math.PI * 180 + config.yaw;
        orientation = true;
        requestAnimationFrame(animate);
    } else {
        config.pitch = q[0] / Math.PI * 180;
        config.roll = -q[1] / Math.PI * 180;
        config.yaw = -q[2] / Math.PI * 180 + orientationYawOffset;
    }
}

Event handler for device orientation API. Controls pointing.
@private
@param {DeviceOrientationEvent} event - Device orientation event.

Event handler for device orientation API . Controls pointing .


function renderInit() {
    try {
        var params = {};
        if (config.horizonPitch !== undefined)
            params.horizonPitch = config.horizonPitch * Math.PI / 180;
        if (config.horizonRoll !== undefined)
            params.horizonRoll = config.horizonRoll * Math.PI / 180;
        if (config.backgroundColor !== undefined)
            params.backgroundColor = config.backgroundColor;
        renderer.init(panoImage, config.type, config.dynamic, config.haov * Math.PI / 180, config.vaov * Math.PI / 180, config.vOffset * Math.PI / 180, renderInitCallback, params);
        if (config.dynamic !== true) {
            // Allow image to be garbage collected
            panoImage = undefined;
        }
    } catch(event) {
        // Panorama not loaded

        // Display error if there is a bad texture
        if (event.type == 'webgl error' || event.type == 'no webgl') {
            anError();
        } else if (event.type == 'webgl size error') {
            anError(config.strings.textureSizeError.replace('%s', event.width).replace('%s', event.maxWidth));
        } else {
            anError(config.strings.unknownError);
            throw event;
        }
    }
}


function renderInitCallback() {
    // Fade if specified
    if (config.sceneFadeDuration && renderer.fadeImg !== undefined) {
        renderer.fadeImg.style.opacity = 0;
        // Remove image
        var fadeImg = renderer.fadeImg;
        delete renderer.fadeImg;
        setTimeout(function() {
            renderContainer.removeChild(fadeImg);
            fireEvent('scenechangefadedone');
        }, config.sceneFadeDuration);
    }

    // Show compass if applicable
    if (config.compass) {
        compass.style.display = 'inline';
    } else {
        compass.style.display = 'none';
    }

    // Show hotspots
    createHotSpots();

    // Hide loading display
    infoDisplay.load.box.style.display = 'none';
    if (preview !== undefined) {
        renderContainer.removeChild(preview);
        preview = undefined;
    }
    loaded = true;

    fireEvent('load');

    animateInit();
}

function
renderInitCallback
(
)
{
// Fade if specified
if
(
config
.
sceneFadeDuration
&&
renderer
.
fadeImg
!==
undefined
)
{
renderer
.
fadeImg
.
style
.
opacity
=
0
;
// Remove image
var
fadeImg
=
renderer
.
fadeImg
;
delete
renderer
.
fadeImg
;
setTimeout
(
function
(
)
{
renderContainer
.
removeChild
(
fadeImg
)
;
fireEvent
(
'scenechangefadedone'
)
;
}
,
config
.
sceneFadeDuration
)
;
}
// Show compass if applicable
if
(
config
.
compass
)
{
compass
.
style
.
display
=
'inline'
;
}
else
{
compass
.
style
.
display
=
'none'
;
}
// Show hotspots
createHotSpots
(
)
;
// Hide loading display
infoDisplay
.
load
.
box
.
style
.
display
=
'none'
;
if
(
preview
!==
undefined
)
{
renderContainer
.
removeChild
(
preview
)
;
preview
=
undefined
;
}
loaded
=
true
;
fireEvent
(
'load'
)
;
animateInit
(
)
;
}

Triggered when render initialization finishes. Handles fading between
scenes as well as showing the compass and hotspots and hiding the loading
display.
@private

Triggered when render initialization finishes . Handles fading between scenes as well as showing the compass and hotspots and hiding the loading display .


function createHotSpots() {
    if (hotspotsCreated) return;

    if (!config.hotSpots) {
        config.hotSpots = [];
    } else {
        // Sort by pitch so tooltip is never obscured by another hot spot
        config.hotSpots = config.hotSpots.sort(function(a, b) {
            return a.pitch < b.pitch;
        });
        config.hotSpots.forEach(createHotSpot);
    }
    hotspotsCreated = true;
    renderHotSpots();
}

Creates hot spot elements for the current scene.
@private

Creates hot spot elements for the current scene .


function destroyHotSpots() {
    var hs = config.hotSpots;
    hotspotsCreated = false;
    delete config.hotSpots;
    if (hs) {
        for (var i = 0; i < hs.length; i++) {
            var current = hs[i].div;
            if (current) {
                while (current.parentNode && current.parentNode != renderContainer) {
                    current = current.parentNode;
                }
                renderContainer.removeChild(current);
            }
            delete hs[i].div;
        }
    }
}

function destroyHotSpots ( ) { var hs = config . hotSpots ; hotspotsCreated = false ; delete config . hotSpots ; if ( hs ) { for ( var i = 0 ; i < hs . length ; i ++ ) { var current = hs [ i ] . div ; if ( current ) { while ( current . parentNode && current . parentNode != renderContainer ) { current = current . parentNode ; } renderContainer . removeChild ( current ) ; } delete hs [ i ] . div ; } } }

Destroys currently created hot spot elements.
@private

Destroys currently created hot spot elements .


function renderHotSpot(hs) {
    var hsPitchSin = Math.sin(hs.pitch * Math.PI / 180),
        hsPitchCos = Math.cos(hs.pitch * Math.PI / 180),
        configPitchSin = Math.sin(config.pitch * Math.PI / 180),
        configPitchCos = Math.cos(config.pitch * Math.PI / 180),
        yawCos = Math.cos((-hs.yaw + config.yaw) * Math.PI / 180);
    var z = hsPitchSin * configPitchSin + hsPitchCos * yawCos * configPitchCos;
    if ((hs.yaw <= 90 && hs.yaw > -90 && z <= 0) ||
      ((hs.yaw > 90 || hs.yaw <= -90) && z <= 0)) {
        hs.div.style.visibility = 'hidden';
    } else {
        var yawSin = Math.sin((-hs.yaw + config.yaw) * Math.PI / 180),
            hfovTan = Math.tan(config.hfov * Math.PI / 360);
        hs.div.style.visibility = 'visible';
        // Subpixel rendering doesn't work in Firefox
        // https://bugzilla.mozilla.org/show_bug.cgi?id=739176
        var canvas = renderer.getCanvas(),
            canvasWidth = canvas.clientWidth,
            canvasHeight = canvas.clientHeight;
        var coord = [-canvasWidth / hfovTan * yawSin * hsPitchCos / z / 2,
            -canvasWidth / hfovTan * (hsPitchSin * configPitchCos -
            hsPitchCos * yawCos * configPitchSin) / z / 2];
        // Apply roll
        var rollSin = Math.sin(config.roll * Math.PI / 180),
            rollCos = Math.cos(config.roll * Math.PI / 180);
        coord = [coord[0] * rollCos - coord[1] * rollSin,
                 coord[0] * rollSin + coord[1] * rollCos];
        // Apply transform
        coord[0] += (canvasWidth - hs.div.offsetWidth) / 2;
        coord[1] += (canvasHeight - hs.div.offsetHeight) / 2;
        var transform = 'translate(' + coord[0] + 'px, ' + coord[1] +
            'px) translateZ(9999px) rotate(' + config.roll + 'deg)';
        hs.div.style.webkitTransform = transform;
        hs.div.style.MozTransform = transform;
        hs.div.style.transform = transform;
    }
}

Renders hot spot, updating its position and visibility.
@private

Renders hot spot updating its position and visibility .


function mergeConfig(sceneId) {
    config = {};
    var k, s;
    var photoSphereExcludes = ['haov', 'vaov', 'vOffset', 'northOffset', 'horizonPitch', 'horizonRoll'];
    specifiedPhotoSphereExcludes = [];

    // Merge default config
    for (k in defaultConfig) {
        if (defaultConfig.hasOwnProperty(k)) {
            config[k] = defaultConfig[k];
        }
    }

    // Merge default scene config
    for (k in initialConfig.default) {
        if (initialConfig.default.hasOwnProperty(k)) {
            if (k == 'strings') {
                for (s in initialConfig.default.strings) {
                    if (initialConfig.default.strings.hasOwnProperty(s)) {
                        config.strings[s] = escapeHTML(initialConfig.default.strings[s]);
                    }
                }
            } else {
                config[k] = initialConfig.default[k];
                if (photoSphereExcludes.indexOf(k) >= 0) {
                    specifiedPhotoSphereExcludes.push(k);
                }
            }
        }
    }

    // Merge current scene config
    if ((sceneId !== null) && (sceneId !== '') && (initialConfig.scenes) && (initialConfig.scenes[sceneId])) {
        var scene = initialConfig.scenes[sceneId];
        for (k in scene) {
            if (scene.hasOwnProperty(k)) {
                if (k == 'strings') {
                    for (s in scene.strings) {
                        if (scene.strings.hasOwnProperty(s)) {
                            config.strings[s] = escapeHTML(scene.strings[s]);
                        }
                    }
                } else {
                    config[k] = scene[k];
                    if (photoSphereExcludes.indexOf(k) >= 0) {
                        specifiedPhotoSphereExcludes.push(k);
                    }
                }
            }
        }
        config.scene = sceneId;
    }

    // Merge initial config
    for (k in initialConfig) {
        if (initialConfig.hasOwnProperty(k)) {
            if (k == 'strings') {
                for (s in initialConfig.strings) {
                    if (initialConfig.strings.hasOwnProperty(s)) {
                        config.strings[s] = escapeHTML(initialConfig.strings[s]);
                    }
                }
            } else {
                config[k] = initialConfig[k];
                if (photoSphereExcludes.indexOf(k) >= 0) {
                    specifiedPhotoSphereExcludes.push(k);
                }
            }
        }
    }
}

function
mergeConfig
(
sceneId
)
{
config
=
{
}
;
var
k
,
s
;
var
photoSphereExcludes
=
[
'haov'
,
'vaov'
,
'vOffset'
,
'northOffset'
,
'horizonPitch'
,
'horizonRoll'
]
;
specifiedPhotoSphereExcludes
=
[
]
;
// Merge default config
for
(
k
in
defaultConfig
)
{
if
(
defaultConfig
.
hasOwnProperty
(
k
)
)
{
config
[
k
]
=
defaultConfig
[
k
]
;
}
}
// Merge default scene config
for
(
k
in
initialConfig
.
default
)
{
if
(
initialConfig
.
default
.
hasOwnProperty
(
k
)
)
{
if
(
k
==
'strings'
)
{
for
(
s
in
initialConfig
.
default
.
strings
)
{
if
(
initialConfig
.
default
.
strings
.
hasOwnProperty
(
s
)
)
{
config
.
strings
[
s
]
=
escapeHTML
(
initialConfig
.
default
.
strings
[
s
]
)
;
}
}
}
else
{
config
[
k
]
=
initialConfig
.
default
[
k
]
;
if
(
photoSphereExcludes
.
indexOf
(
k
)
>=
0
)
{
specifiedPhotoSphereExcludes
.
push
(
k
)
;
}
}
}
}
// Merge current scene config
if
(
(
sceneId
!==
)
&&
(
sceneId
!==
''
)
&&
(
initialConfig
.
scenes
)
&&
(
initialConfig
.
scenes
[
sceneId
]
)
)
{
var
scene
=
initialConfig
.
scenes
[
sceneId
]
;
for
(
k
in
scene
)
{
if
(
scene
.
hasOwnProperty
(
k
)
)
{
if
(
k
==
'strings'
)
{
for
(
s
in
scene
.
strings
)
{
if
(
scene
.
strings
.
hasOwnProperty
(
s
)
)
{
config
.
strings
[
s
]
=
escapeHTML
(
scene
.
strings
[
s
]
)
;
}
}
}
else
{
config
[
k
]
=
scene
[
k
]
;
if
(
photoSphereExcludes
.
indexOf
(
k
)
>=
0
)
{
specifiedPhotoSphereExcludes
.
push
(
k
)
;
}
}
}
}
config
.
scene
=
sceneId
;
}
// Merge initial config
for
(
k
in
initialConfig
)
{
if
(
initialConfig
.
hasOwnProperty
(
k
)
)
{
if
(
k
==
'strings'
)
{
for
(
s
in
initialConfig
.
strings
)
{
if
(
initialConfig
.
strings
.
hasOwnProperty
(
s
)
)
{
config
.
strings
[
s
]
=
escapeHTML
(
initialConfig
.
strings
[
s
]
)
;
}
}
}
else
{
config
[
k
]
=
initialConfig
[
k
]
;
if
(
photoSphereExcludes
.
indexOf
(
k
)
>=
0
)
{
specifiedPhotoSphereExcludes
.
push
(
k
)
;
}
}
}
}
}

Merges a scene configuration into the current configuration.
@private
@param {string} sceneId - Identifier of scene configuration to merge in.

Merges a scene configuration into the current configuration .


function toggleFullscreen() {
    if (loaded && !error) {
        if (!fullscreenActive) {
            try {
                if (container.requestFullscreen) {
                    container.requestFullscreen();
                } else if (container.mozRequestFullScreen) {
                    container.mozRequestFullScreen();
                } else if (container.msRequestFullscreen) {
                    container.msRequestFullscreen();
                } else {
                    container.webkitRequestFullScreen();
                }
            } catch(event) {
                // Fullscreen doesn't work
            }
        } else {
            if (document.exitFullscreen) {
                document.exitFullscreen();
            } else if (document.mozCancelFullScreen) {
                document.mozCancelFullScreen();
            } else if (document.webkitCancelFullScreen) {
                document.webkitCancelFullScreen();
            } else if (document.msExitFullscreen) {
                document.msExitFullscreen();
            }
        }
    }
}

function
toggleFullscreen
(
)
{
if
(
loaded
&&
!
error
)
{
if
(
!
fullscreenActive
)
{
try
{
if
(
container
.
requestFullscreen
)
{
container
.
requestFullscreen
(
)
;
}
else
if
(
container
.
mozRequestFullScreen
)
{
container
.
mozRequestFullScreen
(
)
;
}
else
if
(
container
.
msRequestFullscreen
)
{
container
.
msRequestFullscreen
(
)
;
}
else
{
container
.
webkitRequestFullScreen
(
)
;
}
}
catch
(
event
)
{
// Fullscreen doesn't work
}
}
else
{
if
(
document
.
exitFullscreen
)
{
document
.
exitFullscreen
(
)
;
}
else
if
(
document
.
mozCancelFullScreen
)
{
document
.
mozCancelFullScreen
(
)
;
}
else
if
(
document
.
webkitCancelFullScreen
)
{
document
.
webkitCancelFullScreen
(
)
;
}
else
if
(
document
.
msExitFullscreen
)
{
document
.
msExitFullscreen
(
)
;
}
}
}
}


function onFullScreenChange(resize) {
    if (document.fullscreenElement || document.fullscreen || document.mozFullScreen || document.webkitIsFullScreen || document.msFullscreenElement) {
        controls.fullscreen.classList.add('pnlm-fullscreen-toggle-button-active');
        fullscreenActive = true;
    } else {
        controls.fullscreen.classList.remove('pnlm-fullscreen-toggle-button-active');
        fullscreenActive = false;
    }
    if (resize !== 'resize')
        fireEvent('fullscreenchange', fullscreenActive);
    // Resize renderer (deal with browser quirks and fixes #155)
    renderer.resize();
    setHfov(config.hfov);
    animateInit();
}

Event handler for fullscreen changes.
@private


function constrainHfov(hfov) {
    // Keep field of view within bounds
    var minHfov = config.minHfov;
    if (config.type == 'multires' && renderer && config.multiResMinHfov) {
        minHfov = Math.min(minHfov, renderer.getCanvas().width / (config.multiRes.cubeResolution / 90 * 0.9));
    }
    if (minHfov > config.maxHfov) {
        // Don't change view if bounds don't make sense
        console.log('HFOV bounds do not make sense (minHfov > maxHfov).')
        return config.hfov;
    }
    var newHfov = config.hfov;
    if (hfov < minHfov) {
        newHfov = minHfov;
    } else if (hfov > config.maxHfov) {
        newHfov = config.maxHfov;
    } else {
        newHfov = hfov;
    }
    // Optionally avoid showing background (empty space) on top or bottom by adapting newHfov
    if (config.avoidShowingBackground && renderer) {
        var canvas = renderer.getCanvas();
        newHfov = Math.min(newHfov,
                           Math.atan(Math.tan((config.maxPitch - config.minPitch) / 360 * Math.PI) /
                                     canvas.height * canvas.width)
                               * 360 / Math.PI);
    }
    return newHfov;
}

Clamps horzontal field of view to viewer's limits.
@private
@param {number} hfov - Input horizontal field of view (in degrees)
@return {number} - Clamped horizontal field of view (in degrees)

Clamps horzontal field of view to viewer s limits .


function stopAnimation() {
    animatedMove = {};
    autoRotateSpeed = config.autoRotate ? config.autoRotate : autoRotateSpeed;
    config.autoRotate = false;
}

function stopAnimation ( ) { animatedMove = { } ; autoRotateSpeed = config . autoRotate ? config . autoRotate : autoRotateSpeed ; config . autoRotate = false ; }

Stops auto rotation and animated moves.
@private

Stops auto rotation and animated moves .


function load() {
    // Since WebGL error handling is very general, first we clear any error box
    // since it is a new scene and the error from previous maybe because of lacking
    // memory etc and not because of a lack of WebGL support etc
    clearError();
    loaded = false;

    controls.load.style.display = 'none';
    infoDisplay.load.box.style.display = 'inline';
    init();
}