UNPKG

react-dollyzoom-effect

Version:

A React component for applying a dollyzoom effect to a layout.

609 lines (587 loc) 22.3 kB
(function (global, factory) { if (typeof define === "function" && define.amd) { define(["exports", "react", "react-dom", "velocity-react", "velocity-animate", "lodash", "jquery"], factory); } else if (typeof exports !== "undefined") { factory(exports, require("react"), require("react-dom"), require("velocity-react"), require("velocity-animate"), require("lodash"), require("jquery")); } else { var mod = { exports: {} }; factory(mod.exports, global.react, global.reactDom, global.velocityReact, global.velocityAnimate, global.lodash, global.jquery); global.index_ = mod.exports; } })(this, function (exports, _react, _reactDom, _velocityReact, _velocityAnimate, _lodash, _jquery) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var _react2 = _interopRequireDefault(_react); var _reactDom2 = _interopRequireDefault(_reactDom); var _lodash2 = _interopRequireDefault(_lodash); var _jquery2 = _interopRequireDefault(_jquery); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } // //************************* //************************* // Nonpublished Imports // function updateState(ScopeProxy, Parcel) { var existingState = ScopeProxy.state !== null ? _lodash2.default.cloneDeep(ScopeProxy.state) : {}; var adjustedState = _lodash2.default.merge(existingState, _lodash2.default.cloneDeep(Parcel)); // try { ScopeProxy.setState(adjustedState); } catch (event) { console.warn("::react-dollyzoom:problem::updateState:", event); } } function watch(Testfunction) { var watchCore = { "Match": function Match(Target, Complete, ExpireAt) { var intervalCount = 0; var maximumAttempts = ExpireAt !== undefined ? ExpireAt : 2000; // var watchInterval = setInterval(function () { if (Testfunction() === Target) { Complete(); // clearInterval(watchInterval); } if (intervalCount >= maximumAttempts) { console.warn("react-dollyzoom.js::watch::exceeded watch limit timeout::action halted."); // clearInterval(watchInterval); } intervalCount++; }, 1); // } }; // return watchCore; } // //************************* //************************* // Exports // var Dollyzoom = function (_Component) { _inherits(Dollyzoom, _Component); //************************* //************************* // Standard Methods // function Dollyzoom(props) { _classCallCheck(this, Dollyzoom); return _possibleConstructorReturn(this, (Dollyzoom.__proto__ || Object.getPrototypeOf(Dollyzoom)).call(this, props)); } _createClass(Dollyzoom, [{ key: "getChildContext", value: function getChildContext() { // empty } }, { key: "getInitialState", value: function getInitialState() { return {}; } }, { key: "componentWillMount", value: function componentWillMount() { // empty } }, { key: "componentWillUnmount", value: function componentWillUnmount() { // empty } }, { key: "componentDidMount", value: function componentDidMount() { var scopeProxy = this; // updateState(scopeProxy, { "Ready": false, "Panel": { "Classname": this.props.className }, "Portal": { "Distort": { "Depth": this.props.Portal.Distort.Depth, "Perspective": this.props.Portal.Distort.Perspective, "Blurfactor": this.props.Portal.Distort.Blurfactor, "Fade": this.props.Portal.Distort.Fade, "Zoom": this.props.Portal.Distort.Zoom }, "Morph": { "Apply": { "Easing": this.props.Portal.Morph.Apply.Easing, "Duration": this.props.Portal.Morph.Apply.Duration }, "Restore": { "Easing": this.props.Portal.Morph.Restore.Easing, "Duration": this.props.Portal.Morph.Restore.Duration } }, "Profile": { "runOnMount": false }, "Style": { "display": "inline-block", "position": "relative", "width": "100%", "height": "100%" }, "Ready": this.props.Ready, "Change": this.props.Change, "Complete": this.props.Complete }, "Elements": { //"Style":this.props.Panel.Style, "Classname": this.props.Panel.Classname } }); } }, { key: "componentWillUpdate", value: function componentWillUpdate() { // empty } }, { key: "componentDidUpdate", value: function componentDidUpdate() { var scopeProxy = this; // window.requestAnimationFrame(function () { if (scopeProxy.state !== undefined && scopeProxy.state.Ready === false) { updateState(scopeProxy, { "Ready": true }); scopeProxy.renderDescendents(); } }); } }, { key: "render", value: function render() { var scopeProxy = this; var dollyzoompanelClassname = _lodash2.default.has(this, "state.Panel.Classname") ? this.state.Panel.Classname : null; var dollyzoomportalStyle = _lodash2.default.has(this, "state.Portal.Style") ? this.state.Portal.Style : null; var dollyzoomelementsStyle = _lodash2.default.has(this, "state.Elements.Style") ? this.state.Elements.Style : null; var dollyzoomelementsClassname = _lodash2.default.has(this, "state.Elements.Classname") ? this.state.Elements.Classname : null; var currentTargetSelector = _lodash2.default.has(this, "state.Target.Selector") ? this.state.Target.Selector : null; var dollyzoomsurrogateDisplay = currentTargetSelector !== null && currentTargetSelector !== undefined ? "inline-block" : "none"; // var dollyzoomsurrogateStyle = { "display": dollyzoomsurrogateDisplay, "position": "absolute", "top": "0", "left": "0", "width": "100%", "height": "100%" }; // var portalmorphProfileOnmount = { "runOnMount": false }; // var portalmorphStyle = { "display": "block", "position": "absolute", "visibility": "hidden", "opacity": "0", "top": "0", "left": "0", "width": "0", "height": "0" }; // var dollyzoomchildrenStyle = { "display": "none", "position": "absolute" }; // var portalmorphProfile = _lodash2.default.has(this, "state.Portal.Profile") ? this.state.Portal.Profile : portalmorphProfileOnmount; // return _react2.default.createElement( "div", { id: "dollyzoom-panel-container", ref: "dollyzoompanel", className: dollyzoompanelClassname }, _react2.default.createElement( "div", { id: "dollyzoom-elements-containter", ref: "dollyzoomelements", style: dollyzoomelementsStyle, className: dollyzoomelementsClassname }, _react2.default.createElement("div", { id: "dollyzoom-portal-container", ref: "dollyzoomportal", style: dollyzoomportalStyle }), _react2.default.createElement("div", { id: "dollyzoom-surrogate-container", ref: "dollyzoomsurrogate", style: dollyzoomsurrogateStyle }), _react2.default.createElement( "div", { id: "dollyzoom-children-container", ref: "dollyzoomchildren", style: dollyzoomchildrenStyle }, this.props.children ) ), _react2.default.createElement( _velocityReact.VelocityComponent, portalmorphProfile, _react2.default.createElement("div", { id: "portal-morph-container", ref: "portalmorph", style: portalmorphStyle }) ) ); } }, { key: "setListeners", value: function setListeners() { var scopeProxy = this; // } }, { key: "renderDescendents", value: function renderDescendents() { var scopeProxy = this; // watch(function () { return _typeof(scopeProxy.state); }).Match("object", function () { var hostId = scopeProxy.props.Host.Id; var portalSelectorPath = "#".concat(hostId, " #dollyzoom-portal-container"); var surrogateSelectorPath = "#".concat(hostId, " #dollyzoom-surrogate-container"); var childrenSelectorPath = "#".concat(hostId, " #dollyzoom-children-container"); var portalTargetnode = (0, _jquery2.default)(portalSelectorPath)[0]; var surrogateTargetnode = (0, _jquery2.default)(surrogateSelectorPath)[0]; // // ******************** // ******************** // nonflux-pattern // Use jQuery to perform the deep cloning in conjunction with assigning // the event listeners attached to the content of the dollyzoom elements // container. Attaching event listeners using jQuery allows jQuery to // easily deep clone (with listeners) the elements. var sourceclonePortal = (0, _jquery2.default)(childrenSelectorPath).children(0).clone(true, true)[0]; var sourcecloneSurrogate = (0, _jquery2.default)(childrenSelectorPath).children(0).clone(true, true)[0]; // ******************** // ******************** portalTargetnode.appendChild(sourceclonePortal); surrogateTargetnode.appendChild(sourcecloneSurrogate); // window.requestAnimationFrame(function () { scopeProxy.state.Portal.Ready({ "children": scopeProxy.props.children }); }); }); } }, { key: "onChange", value: function onChange(Parcel) { // empty } }, { key: "dollyzoomApply", value: function dollyzoomApply(Parcel) { var scopeProxy = this; var targetId = Parcel.Targetid; var onComplete = Parcel.Complete; var hostId = this.props.Host.Id; var targetSelector = "#".concat(targetId); var currentTargetSelector = _lodash2.default.has(this, "state.Target.Selector") ? this.state.Target.Selector : undefined; var targetSelectorPath = "#".concat(hostId, " #dollyzoom-surrogate-container ", targetSelector); var portalRef = this.refs.dollyzoomportal; var surrogateRef = this.refs.dollyzoomsurrogate; var portalChildelement // get the portal child = portalRef.firstChild; var surrogateChildelement // get the descendents child = surrogateRef.firstChild; var portalChildelementContent // get the targetElement from within the portal child = portalChildelement.querySelector(targetSelector); var surrogateChildelementContent // get the targetElement from within the descendents child = surrogateChildelement.querySelector(targetSelector); var initialChildelementScale = 1; var morphEasing = this.state.Portal.Morph.Apply.Easing; var morphDuration = this.state.Portal.Morph.Apply.Duration; var distortDepth = this.state.Portal.Distort.Depth; var distortDepthUnit = distortDepth.match(/([A-Z,a-z])\w+/g)[0]; var distortBlurfactor = this.state.Portal.Distort.Blurfactor; var distortBlurUnit = distortBlurfactor.match(/([A-Z,a-z])\w+/g)[0]; var distortPerspective = this.state.Portal.Distort.Perspective; var distortFade = this.state.Portal.Distort.Fade; var distortZoom = this.state.Portal.Distort.Zoom; // var portalProfile = { "Profile": { "duration": morphDuration, "easing": morphEasing, "runOnMount": false, "animation": { "opacity": 1 }, "progress": function progress(elements, complete, remaining, start, tweenValue) { // http://velocityjs.org/ // The value of tweenValue is being reported as null for // unknown reasons. In order to tween the rotation according // to the easing, the actual value of the opacity must be // used as it tweens from zero to one. Additionally, at the // completion of the tween, the value of the opacity is set // back to zero by Velocity. This must be avoided so that the // rotation of the sections does not revert to its original // rotation value. // var progressValue = elements[0].style.opacity > 0 ? elements[0].style.opacity : 1; var translateValue = (parseInt(distortDepth) * progressValue).toString().concat(distortDepthUnit); var blurValue = (Math.abs(parseInt(distortDepth)) * progressValue * parseFloat(distortBlurfactor)).toString().concat(distortBlurUnit); var opacityValue = 1 - (1 - distortFade) * progressValue; var grayscaleValue = ((1 - distortFade) * progressValue * 100).toString().concat("%"); var zoomValue = (parseFloat(distortZoom) - parseFloat(initialChildelementScale)) * progressValue + parseFloat(initialChildelementScale); var transformValue = "translateZ(".concat(translateValue, ")"); // updateState(scopeProxy, { "Portal": { "Style": { "display": "inline-block", "position": "relative", "transform": transformValue, "filter": "blur(".concat(blurValue, ") grayscale(", grayscaleValue, ")"), "opacity": opacityValue } } }); Object.assign(surrogateChildelementContent.style, { "transform": "scale(".concat(zoomValue.toString(), ")") }); scopeProxy.state.Portal.Change({ "Style": { "transform": transformValue, "filter": "blur(".concat(blurValue, ") grayscale(", grayscaleValue, ")"), "opacity": opacityValue }, "Target": { "Selector": targetSelector, "transform": "scale(".concat(zoomValue.toString(), ")") } }); }, "complete": function complete(event) { scopeProxy.state.Portal.Complete({ "Action": "dollyzoomApply", "Target": targetSelector }); onComplete(document.querySelector(targetSelectorPath)); } } }; // if (currentTargetSelector !== null && currentTargetSelector !== undefined) { this.dollyzoomRestore(currentTargetSelector.split("#")[1]); } else { Object.assign(portalChildelementContent.style, { "visibility": "hidden" // hide targetElement within the dollyzoomPortal element }); Object.assign(surrogateChildelement.style, { "visibility": "hidden" // hides all child elements of the dollyzoomDescendents element }); Object.assign(surrogateChildelementContent.style, { "visibility": "visible" // forces targetElement to be visible within the dollyzoomDescendents element }); updateState(scopeProxy, { "Portal": portalProfile, "Elements": { "Style": { "display": "inline-block", "position": "relative", "transform-style": "preserve-3d", "perspective": distortPerspective } }, "Target": { "Selector": targetSelector } }); } } }, { key: "dollyzoomRestore", value: function dollyzoomRestore() { var scopeProxy = this; var hostId = this.props.Host.Id; var targetSelector = this.state.Target.Selector; var currentTargetSelector = this.state.Target.Selector; var targetSelectorPath = "#".concat(hostId, " #dollyzoom-surrogate-container ", targetSelector); var portalRef = this.refs.dollyzoomportal; var surrogateRef = this.refs.dollyzoomsurrogate; var portalChildelement // get the portal child = portalRef.firstChild; var surrogateChildelement // get the descendents child = surrogateRef.firstChild; var portalChildelementContent // get the targetElement from within the portal child = portalChildelement.querySelector(targetSelectorPath); var surrogateChildelementContent // get the targetElement from within the descendents child = surrogateChildelement.querySelector(targetSelectorPath); var initialChildelementScale = 1; var morphEasing = this.state.Portal.Morph.Restore.Easing; var morphDuration = this.state.Portal.Morph.Restore.Duration; var distortDepth = this.state.Portal.Distort.Depth; var distortDepthUnit = distortDepth.match(/([A-Z,a-z])\w+/g)[0]; var distortBlurfactor = this.state.Portal.Distort.Blurfactor; var distortBlurUnit = distortBlurfactor.match(/([A-Z,a-z])\w+/g)[0]; var distortPerspective = this.state.Portal.Distort.Perspective; var distortFade = this.state.Portal.Distort.Fade; var distortZoom = this.state.Portal.Distort.Zoom; // var portalProfile = { "Profile": { "duration": morphDuration, "easing": morphEasing, "runOnMount": false, "animation": { "opacity": 0 }, "progress": function progress(elements, complete, remaining, start, tweenValue) { // http://velocityjs.org/ // The value of tweenValue is being reported as null for // unknown reasons. In order to tween the rotation according // to the easing, the actual value of the opacity must be // used as it tweens from zero to one. Additionally, at the // completion of the tween, the value of the opacity is set // back to zero by Velocity. This must be avoided so that the // rotation of the sections does not revert to its original // rotation value. // var progressValue = elements[0].style.opacity > 0 ? elements[0].style.opacity : 0; var translateValue = (parseInt(distortDepth) * progressValue).toString().concat(distortDepthUnit); var blurValue = (Math.abs(parseInt(distortDepth)) * progressValue * parseFloat(distortBlurfactor)).toString().concat(distortBlurUnit); var opacityValue = 1 - (1 - distortFade) * progressValue; var grayscaleValue = ((1 - distortFade) * progressValue * 100).toString().concat("%"); var zoomValue = (parseFloat(distortZoom) - parseFloat(initialChildelementScale)) * progressValue + parseFloat(initialChildelementScale); var transformValue = "translateZ(".concat(translateValue, ")"); // updateState(scopeProxy, { "Portal": { "Style": { "display": "inline-block", "position": "relative", "transform": transformValue, "filter": "blur(".concat(blurValue, ") grayscale(", grayscaleValue, ")"), "opacity": opacityValue } } }); Object.assign(surrogateChildelementContent.style, { "transform": "scale(".concat(zoomValue.toString(), ")") }); scopeProxy.state.Portal.Change({ "Style": { "transform": transformValue, "filter": "blur(".concat(blurValue, ") grayscale(", grayscaleValue, ")"), "opacity": opacityValue }, "Target": { "Selector": targetSelector, "transform": "scale(".concat(zoomValue.toString(), ")") } }); }, "complete": function complete(event) { var hostId = scopeProxy.props.Host.Id; var portalSelectorPath = "#".concat(hostId, " #dollyzoom-portal-container"); var surrogateSelectorPath = "#".concat(hostId, " #dollyzoom-surrogate-container"); // ******************** // ******************** // nonflux-pattern // Use jQuery to perform the deep cloning in conjunction with assigning // the event listeners attached to the content of the dollyzoom elements // container. Attaching event listeners using jQuery allows jQuery to // easily deep clone (with listeners) the elements. var surrogateContent = (0, _jquery2.default)(surrogateSelectorPath).clone(true, true); // (0, _jquery2.default)(portalSelectorPath).html((0, _jquery2.default)(surrogateContent).children()); // (0, _jquery2.default)(portalSelectorPath).children(0).css("visibility", "inherit"); // ******************** // ******************** // Object.assign(surrogateChildelementContent.style, { "visibility": "inherit" // reset visibility to default flow }); updateState(scopeProxy, { "Target": { "Selector": null } }); scopeProxy.state.Portal.Complete({ "Action": "dollyzoomRestore", "Target": targetSelector }); } } }; // if (targetSelector !== null) { updateState(scopeProxy, { "Portal": portalProfile, "Elements": { "Style": { "display": "inline-block", "position": "relative", "transform-style": "preserve-3d", "perspective": distortPerspective } } }); } else { console.warn("react-dollyzoom.js::dollyzoomRestort::dollyzoomRestore called before dollyzoomApply::action halted."); } } }]); return Dollyzoom; }(_react.Component); Dollyzoom.contextTypes = {} // empty // ; exports.default = Dollyzoom; });