blob: 13e0ef9e2ade22bad8c14eb58fa74eca4d5671ca [file] [log] [blame]
<!--
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-->
<import src="animation/controller.sky" as="AnimationController" />
<import src="animation/curves.sky" as="Curves" />
<import src="sky-element/sky-element.sky" as="SkyElement" />
<import src="sky-scrollable.sky" />
<sky-element
name="sky-drawer"
on-pointerdown="handlePointerDown"
on-pointermove="handlePointerMove"
on-pointerup="handlePointerUp"
on-pointercancel="handlePointerCancel">
<template>
<style>
#mask {
background-color: black;
will-change: opacity;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
#content {
background-color: yellow;
will-change: transform;
position: absolute;
width: 256px;
top: 0;
left: 0;
bottom: 0;
}
</style>
<div id="mask" on-click="handleMaskClick" />
<div id="content" on-gestureflingstart="handleFlingStart">
<content/>
</div>
</template>
<script>
const kWidth = 256;
const kMinFlingVelocity = 0.4;
const kMinAnimationDurationMS = 246;
const kMaxAnimationDurationMS = 600;
const kAnimationCurve = Curves.easeInOut;
module.exports = class extends SkyElement {
created() {
this.position_ = 0;
this.mask_ = null;
this.content_ = null;
this.animation_ = new AnimationController(this);
}
shadowRootReady() {
this.mask_ = this.shadowRoot.getElementById('mask');
this.content_ = this.shadowRoot.getElementById('content');
this.position = -kWidth;
}
toggle() {
if (this.isMostlyClosed)
this.open();
else
this.close();
}
open() {
this.animateToPosition_(0);
}
close() {
this.animateToPosition_(-kWidth);
}
get isClosed() {
return this.position_ <= -kWidth;
}
get isMostlyClosed() {
return this.position_ <= -kWidth / 2;
}
get position() {
return this.position_;
}
set position(value) {
var newPosition = Math.min(0, Math.max(value, -kWidth));
this.position_ = newPosition;
this.content_.style.transform = 'translateX(' + newPosition + 'px)';
this.mask_.style.opacity = (newPosition / kWidth + 1) * 0.25;
this.style.display = this.isClosed ? 'none' : '';
}
settle_() {
if (this.isMostlyClosed)
this.close();
else
this.open();
}
animateToPosition_(targetPosition) {
var currentPosition = this.position_;
var distance = Math.abs(targetPosition - currentPosition);
var duration = kMaxAnimationDurationMS * distance / kWidth;
this.animation_.start({
begin: currentPosition,
end: targetPosition,
duration: Math.max(kMinAnimationDurationMS, duration),
curve: kAnimationCurve,
});
}
updateAnimation(position) {
this.position = position;
}
handleMaskClick() {
this.close();
}
handlePointerDown(event) {
this.animation_.stop();
}
handlePointerMove(event) {
this.position += event.dx;
}
handlePointerUp(event) {
if (!this.animation_.isAnimating)
this.settle_();
}
handlePointerCancel(event) {
if (!this.animation_.isAnimating)
this.settle_();
}
handleFlingStart(event) {
var direction = Math.sign(event.velocityX);
var velocityX = Math.abs(event.velocityX) / 1000;
if (velocityX < kMinFlingVelocity)
return;
var targetPosition = direction < 0 ? -kWidth : 0;
var currentPosition = this.position_;
var distance = Math.abs(targetPosition - currentPosition);
var duration = distance / velocityX;
this.animation_.start({
begin: currentPosition,
end: targetPosition,
duration: duration,
curve: Curves.linear,
});
}
}.register();
</script>
</sky-element>