UNPKG

bytev-charts

Version:

基于echarts和JavaScript及ES6封装的一个可以直接调用的图表组件库,内置主题设计,简单快捷,且支持用户自定义配置; npm 安装方式: npm install bytev-charts 若启动提示还需额外install插件,则运行 npm install @babel/runtime-corejs2 即可;

733 lines (619 loc) 24.4 kB
import _WeakMap from "@babel/runtime-corejs2/core-js/weak-map"; import _Array$isArray from "@babel/runtime-corejs2/core-js/array/is-array"; import "core-js/modules/es.function.name.js"; import "core-js/modules/es.array.index-of.js"; import "core-js/modules/es.array.slice.js"; import "core-js/modules/es.array.iterator.js"; import "core-js/modules/es.array-buffer.slice.js"; import "core-js/modules/es.object.to-string.js"; import "core-js/modules/es.typed-array.float32-array.js"; import "core-js/modules/es.typed-array.copy-within.js"; import "core-js/modules/es.typed-array.every.js"; import "core-js/modules/es.typed-array.fill.js"; import "core-js/modules/es.typed-array.filter.js"; import "core-js/modules/es.typed-array.find.js"; import "core-js/modules/es.typed-array.find-index.js"; import "core-js/modules/es.typed-array.for-each.js"; import "core-js/modules/es.typed-array.includes.js"; import "core-js/modules/es.typed-array.index-of.js"; import "core-js/modules/es.typed-array.iterator.js"; import "core-js/modules/es.typed-array.join.js"; import "core-js/modules/es.typed-array.last-index-of.js"; import "core-js/modules/es.typed-array.map.js"; import "core-js/modules/es.typed-array.reduce.js"; import "core-js/modules/es.typed-array.reduce-right.js"; import "core-js/modules/es.typed-array.reverse.js"; import "core-js/modules/es.typed-array.set.js"; import "core-js/modules/es.typed-array.slice.js"; import "core-js/modules/es.typed-array.some.js"; import "core-js/modules/es.typed-array.sort.js"; import "core-js/modules/es.typed-array.subarray.js"; import "core-js/modules/es.typed-array.to-locale-string.js"; import "core-js/modules/es.typed-array.to-string.js"; import "core-js/modules/es.promise.js"; console.warn("THREE.MMDAnimationHelper: As part of the transition to ES6 Modules, the files in 'examples/js' were deprecated in May 2020 (r117) and will be deleted in December 2020 (r124). You can find more information about developing using ES6 Modules in https://threejs.org/docs/#manual/en/introduction/Installation."); /** * MMDAnimationHelper handles animation of MMD assets loaded by MMDLoader * with MMD special features as IK, Grant, and Physics. * * Dependencies * - ammo.js https://github.com/kripken/ammo.js * - THREE.MMDPhysics * - THREE.CCDIKSolver * * TODO * - more precise grant skinning support. */ THREE.MMDAnimationHelper = function () { /** * @param {Object} params - (optional) * @param {boolean} params.sync - Whether animation durations of added objects are synched. Default is true. * @param {Number} params.afterglow - Default is 0.0. * @param {boolean} params.resetPhysicsOnLoop - Default is true. */ function MMDAnimationHelper(params) { params = params || {}; this.meshes = []; this.camera = null; this.cameraTarget = new THREE.Object3D(); this.cameraTarget.name = 'target'; this.audio = null; this.audioManager = null; this.objects = new _WeakMap(); this.configuration = { sync: params.sync !== undefined ? params.sync : true, afterglow: params.afterglow !== undefined ? params.afterglow : 0.0, resetPhysicsOnLoop: params.resetPhysicsOnLoop !== undefined ? params.resetPhysicsOnLoop : true }; this.enabled = { animation: true, ik: true, grant: true, physics: true, cameraAnimation: true }; this.onBeforePhysics = function /* mesh */ () {}; // experimental this.sharedPhysics = false; this.masterPhysics = null; } MMDAnimationHelper.prototype = { constructor: MMDAnimationHelper, /** * Adds an Three.js Object to helper and setups animation. * The anmation durations of added objects are synched * if this.configuration.sync is true. * * @param {THREE.SkinnedMesh|THREE.Camera|THREE.Audio} object * @param {Object} params - (optional) * @param {THREE.AnimationClip|Array<THREE.AnimationClip>} params.animation - Only for THREE.SkinnedMesh and THREE.Camera. Default is undefined. * @param {boolean} params.physics - Only for THREE.SkinnedMesh. Default is true. * @param {Integer} params.warmup - Only for THREE.SkinnedMesh and physics is true. Default is 60. * @param {Number} params.unitStep - Only for THREE.SkinnedMesh and physics is true. Default is 1 / 65. * @param {Integer} params.maxStepNum - Only for THREE.SkinnedMesh and physics is true. Default is 3. * @param {THREE.Vector3} params.gravity - Only for THREE.SkinnedMesh and physics is true. Default ( 0, - 9.8 * 10, 0 ). * @param {Number} params.delayTime - Only for THREE.Audio. Default is 0.0. * @return {THREE.MMDAnimationHelper} */ add: function add(object, params) { params = params || {}; if (object.isSkinnedMesh) { this._addMesh(object, params); } else if (object.isCamera) { this._setupCamera(object, params); } else if (object.type === 'Audio') { this._setupAudio(object, params); } else { throw new Error('THREE.MMDAnimationHelper.add: ' + 'accepts only ' + 'THREE.SkinnedMesh or ' + 'THREE.Camera or ' + 'THREE.Audio instance.'); } if (this.configuration.sync) this._syncDuration(); return this; }, /** * Removes an Three.js Object from helper. * * @param {THREE.SkinnedMesh|THREE.Camera|THREE.Audio} object * @return {THREE.MMDAnimationHelper} */ remove: function remove(object) { if (object.isSkinnedMesh) { this._removeMesh(object); } else if (object.isCamera) { this._clearCamera(object); } else if (object.type === 'Audio') { this._clearAudio(object); } else { throw new Error('THREE.MMDAnimationHelper.remove: ' + 'accepts only ' + 'THREE.SkinnedMesh or ' + 'THREE.Camera or ' + 'THREE.Audio instance.'); } if (this.configuration.sync) this._syncDuration(); return this; }, /** * Updates the animation. * * @param {Number} delta * @return {THREE.MMDAnimationHelper} */ update: function update(delta) { if (this.audioManager !== null) this.audioManager.control(delta); for (var i = 0; i < this.meshes.length; i++) { this._animateMesh(this.meshes[i], delta); } if (this.sharedPhysics) this._updateSharedPhysics(delta); if (this.camera !== null) this._animateCamera(this.camera, delta); return this; }, /** * Changes the pose of SkinnedMesh as VPD specifies. * * @param {THREE.SkinnedMesh} mesh * @param {Object} vpd - VPD content parsed MMDParser * @param {Object} params - (optional) * @param {boolean} params.resetPose - Default is true. * @param {boolean} params.ik - Default is true. * @param {boolean} params.grant - Default is true. * @return {THREE.MMDAnimationHelper} */ pose: function pose(mesh, vpd, params) { params = params || {}; if (params.resetPose !== false) mesh.pose(); var bones = mesh.skeleton.bones; var boneParams = vpd.bones; var boneNameDictionary = {}; for (var i = 0, il = bones.length; i < il; i++) { boneNameDictionary[bones[i].name] = i; } var vector = new THREE.Vector3(); var quaternion = new THREE.Quaternion(); for (var i = 0, il = boneParams.length; i < il; i++) { var boneParam = boneParams[i]; var boneIndex = boneNameDictionary[boneParam.name]; if (boneIndex === undefined) continue; var bone = bones[boneIndex]; bone.position.add(vector.fromArray(boneParam.translation)); bone.quaternion.multiply(quaternion.fromArray(boneParam.quaternion)); } mesh.updateMatrixWorld(true); if (params.ik !== false) { this._createCCDIKSolver(mesh).update(params.saveOriginalBonesBeforeIK); // this param is experimental } if (params.grant !== false) { this.createGrantSolver(mesh).update(); } return this; }, /** * Enabes/Disables an animation feature. * * @param {string} key * @param {boolean} enabled * @return {THREE.MMDAnimationHelper} */ enable: function enable(key, enabled) { if (this.enabled[key] === undefined) { throw new Error('THREE.MMDAnimationHelper.enable: ' + 'unknown key ' + key); } this.enabled[key] = enabled; if (key === 'physics') { for (var i = 0, il = this.meshes.length; i < il; i++) { this._optimizeIK(this.meshes[i], enabled); } } return this; }, /** * Creates an GrantSolver instance. * * @param {THREE.SkinnedMesh} mesh * @return {GrantSolver} */ createGrantSolver: function createGrantSolver(mesh) { return new GrantSolver(mesh, mesh.geometry.userData.MMD.grants); }, // private methods _addMesh: function _addMesh(mesh, params) { if (this.meshes.indexOf(mesh) >= 0) { throw new Error('THREE.MMDAnimationHelper._addMesh: ' + 'SkinnedMesh \'' + mesh.name + '\' has already been added.'); } this.meshes.push(mesh); this.objects.set(mesh, { looped: false }); this._setupMeshAnimation(mesh, params.animation); if (params.physics !== false) { this._setupMeshPhysics(mesh, params); } return this; }, _setupCamera: function _setupCamera(camera, params) { if (this.camera === camera) { throw new Error('THREE.MMDAnimationHelper._setupCamera: ' + 'Camera \'' + camera.name + '\' has already been set.'); } if (this.camera) this.clearCamera(this.camera); this.camera = camera; camera.add(this.cameraTarget); this.objects.set(camera, {}); if (params.animation !== undefined) { this._setupCameraAnimation(camera, params.animation); } return this; }, _setupAudio: function _setupAudio(audio, params) { if (this.audio === audio) { throw new Error('THREE.MMDAnimationHelper._setupAudio: ' + 'Audio \'' + audio.name + '\' has already been set.'); } if (this.audio) this.clearAudio(this.audio); this.audio = audio; this.audioManager = new AudioManager(audio, params); this.objects.set(this.audioManager, { duration: this.audioManager.duration }); return this; }, _removeMesh: function _removeMesh(mesh) { var found = false; var writeIndex = 0; for (var i = 0, il = this.meshes.length; i < il; i++) { if (this.meshes[i] === mesh) { this.objects["delete"](mesh); found = true; continue; } this.meshes[writeIndex++] = this.meshes[i]; } if (!found) { throw new Error('THREE.MMDAnimationHelper._removeMesh: ' + 'SkinnedMesh \'' + mesh.name + '\' has not been added yet.'); } this.meshes.length = writeIndex; return this; }, _clearCamera: function _clearCamera(camera) { if (camera !== this.camera) { throw new Error('THREE.MMDAnimationHelper._clearCamera: ' + 'Camera \'' + camera.name + '\' has not been set yet.'); } this.camera.remove(this.cameraTarget); this.objects["delete"](this.camera); this.camera = null; return this; }, _clearAudio: function _clearAudio(audio) { if (audio !== this.audio) { throw new Error('THREE.MMDAnimationHelper._clearAudio: ' + 'Audio \'' + audio.name + '\' has not been set yet.'); } this.objects["delete"](this.audioManager); this.audio = null; this.audioManager = null; return this; }, _setupMeshAnimation: function _setupMeshAnimation(mesh, animation) { var objects = this.objects.get(mesh); if (animation !== undefined) { var animations = _Array$isArray(animation) ? animation : [animation]; objects.mixer = new THREE.AnimationMixer(mesh); for (var i = 0, il = animations.length; i < il; i++) { objects.mixer.clipAction(animations[i]).play(); } // TODO: find a workaround not to access ._clip looking like a private property objects.mixer.addEventListener('loop', function (event) { var tracks = event.action._clip.tracks; if (tracks.length > 0 && tracks[0].name.slice(0, 6) !== '.bones') return; objects.looped = true; }); } objects.ikSolver = this._createCCDIKSolver(mesh); objects.grantSolver = this.createGrantSolver(mesh); return this; }, _setupCameraAnimation: function _setupCameraAnimation(camera, animation) { var animations = _Array$isArray(animation) ? animation : [animation]; var objects = this.objects.get(camera); objects.mixer = new THREE.AnimationMixer(camera); for (var i = 0, il = animations.length; i < il; i++) { objects.mixer.clipAction(animations[i]).play(); } }, _setupMeshPhysics: function _setupMeshPhysics(mesh, params) { var objects = this.objects.get(mesh); // shared physics is experimental if (params.world === undefined && this.sharedPhysics) { var masterPhysics = this._getMasterPhysics(); if (masterPhysics !== null) world = masterPhysics.world; // eslint-disable-line no-undef } objects.physics = this._createMMDPhysics(mesh, params); if (objects.mixer && params.animationWarmup !== false) { this._animateMesh(mesh, 0); objects.physics.reset(); } objects.physics.warmup(params.warmup !== undefined ? params.warmup : 60); this._optimizeIK(mesh, true); }, _animateMesh: function _animateMesh(mesh, delta) { var objects = this.objects.get(mesh); var mixer = objects.mixer; var ikSolver = objects.ikSolver; var grantSolver = objects.grantSolver; var physics = objects.physics; var looped = objects.looped; // alternate solution to save/restore bones but less performant? //mesh.pose(); //this._updatePropertyMixersBuffer( mesh ); if (mixer && this.enabled.animation) { this._restoreBones(mesh); mixer.update(delta); this._saveBones(mesh); if (ikSolver && this.enabled.ik) { mesh.updateMatrixWorld(true); ikSolver.update(); } if (grantSolver && this.enabled.grant) { grantSolver.update(); } } if (looped === true && this.enabled.physics) { if (physics && this.configuration.resetPhysicsOnLoop) physics.reset(); objects.looped = false; } if (physics && this.enabled.physics && !this.sharedPhysics) { this.onBeforePhysics(mesh); physics.update(delta); } }, _animateCamera: function _animateCamera(camera, delta) { var mixer = this.objects.get(camera).mixer; if (mixer && this.enabled.cameraAnimation) { mixer.update(delta); camera.updateProjectionMatrix(); camera.up.set(0, 1, 0); camera.up.applyQuaternion(camera.quaternion); camera.lookAt(this.cameraTarget.position); } }, _optimizeIK: function _optimizeIK(mesh, physicsEnabled) { var iks = mesh.geometry.userData.MMD.iks; var bones = mesh.geometry.userData.MMD.bones; for (var i = 0, il = iks.length; i < il; i++) { var ik = iks[i]; var links = ik.links; for (var j = 0, jl = links.length; j < jl; j++) { var link = links[j]; if (physicsEnabled === true) { // disable IK of the bone the corresponding rigidBody type of which is 1 or 2 // because its rotation will be overriden by physics link.enabled = bones[link.index].rigidBodyType > 0 ? false : true; } else { link.enabled = true; } } } }, _createCCDIKSolver: function _createCCDIKSolver(mesh) { if (THREE.CCDIKSolver === undefined) { throw new Error('THREE.MMDAnimationHelper: Import THREE.CCDIKSolver.'); } return new THREE.CCDIKSolver(mesh, mesh.geometry.userData.MMD.iks); }, _createMMDPhysics: function _createMMDPhysics(mesh, params) { if (THREE.MMDPhysics === undefined) { throw new Error('THREE.MMDPhysics: Import THREE.MMDPhysics.'); } return new THREE.MMDPhysics(mesh, mesh.geometry.userData.MMD.rigidBodies, mesh.geometry.userData.MMD.constraints, params); }, /* * Detects the longest duration and then sets it to them to sync. * TODO: Not to access private properties ( ._actions and ._clip ) */ _syncDuration: function _syncDuration() { var max = 0.0; var objects = this.objects; var meshes = this.meshes; var camera = this.camera; var audioManager = this.audioManager; // get the longest duration for (var i = 0, il = meshes.length; i < il; i++) { var mixer = this.objects.get(meshes[i]).mixer; if (mixer === undefined) continue; for (var j = 0; j < mixer._actions.length; j++) { var clip = mixer._actions[j]._clip; if (!objects.has(clip)) { objects.set(clip, { duration: clip.duration }); } max = Math.max(max, objects.get(clip).duration); } } if (camera !== null) { var mixer = this.objects.get(camera).mixer; if (mixer !== undefined) { for (var i = 0, il = mixer._actions.length; i < il; i++) { var clip = mixer._actions[i]._clip; if (!objects.has(clip)) { objects.set(clip, { duration: clip.duration }); } max = Math.max(max, objects.get(clip).duration); } } } if (audioManager !== null) { max = Math.max(max, objects.get(audioManager).duration); } max += this.configuration.afterglow; // update the duration for (var i = 0, il = this.meshes.length; i < il; i++) { var mixer = this.objects.get(this.meshes[i]).mixer; if (mixer === undefined) continue; for (var j = 0, jl = mixer._actions.length; j < jl; j++) { mixer._actions[j]._clip.duration = max; } } if (camera !== null) { var mixer = this.objects.get(camera).mixer; if (mixer !== undefined) { for (var i = 0, il = mixer._actions.length; i < il; i++) { mixer._actions[i]._clip.duration = max; } } } if (audioManager !== null) { audioManager.duration = max; } }, // workaround _updatePropertyMixersBuffer: function _updatePropertyMixersBuffer(mesh) { var mixer = this.objects.get(mesh).mixer; var propertyMixers = mixer._bindings; var accuIndex = mixer._accuIndex; for (var i = 0, il = propertyMixers.length; i < il; i++) { var propertyMixer = propertyMixers[i]; var buffer = propertyMixer.buffer; var stride = propertyMixer.valueSize; var offset = (accuIndex + 1) * stride; propertyMixer.binding.getValue(buffer, offset); } }, /* * Avoiding these two issues by restore/save bones before/after mixer animation. * * 1. PropertyMixer used by AnimationMixer holds cache value in .buffer. * Calculating IK, Grant, and Physics after mixer animation can break * the cache coherency. * * 2. Applying Grant two or more times without reset the posing breaks model. */ _saveBones: function _saveBones(mesh) { var objects = this.objects.get(mesh); var bones = mesh.skeleton.bones; var backupBones = objects.backupBones; if (backupBones === undefined) { backupBones = new Float32Array(bones.length * 7); objects.backupBones = backupBones; } for (var i = 0, il = bones.length; i < il; i++) { var bone = bones[i]; bone.position.toArray(backupBones, i * 7); bone.quaternion.toArray(backupBones, i * 7 + 3); } }, _restoreBones: function _restoreBones(mesh) { var objects = this.objects.get(mesh); var backupBones = objects.backupBones; if (backupBones === undefined) return; var bones = mesh.skeleton.bones; for (var i = 0, il = bones.length; i < il; i++) { var bone = bones[i]; bone.position.fromArray(backupBones, i * 7); bone.quaternion.fromArray(backupBones, i * 7 + 3); } }, // experimental _getMasterPhysics: function _getMasterPhysics() { if (this.masterPhysics !== null) return this.masterPhysics; for (var i = 0, il = this.meshes.length; i < il; i++) { var physics = this.meshes[i].physics; if (physics !== undefined && physics !== null) { this.masterPhysics = physics; return this.masterPhysics; } } return null; }, _updateSharedPhysics: function _updateSharedPhysics(delta) { if (this.meshes.length === 0 || !this.enabled.physics || !this.sharedPhysics) return; var physics = this._getMasterPhysics(); if (physics === null) return; for (var i = 0, il = this.meshes.length; i < il; i++) { var p = this.meshes[i].physics; if (p !== null && p !== undefined) { p.updateRigidBodies(); } } physics.stepSimulation(delta); for (var i = 0, il = this.meshes.length; i < il; i++) { var p = this.meshes[i].physics; if (p !== null && p !== undefined) { p.updateBones(); } } } }; // /** * @param {THREE.Audio} audio * @param {Object} params - (optional) * @param {Nuumber} params.delayTime */ function AudioManager(audio, params) { params = params || {}; this.audio = audio; this.elapsedTime = 0.0; this.currentTime = 0.0; this.delayTime = params.delayTime !== undefined ? params.delayTime : 0.0; this.audioDuration = this.audio.buffer.duration; this.duration = this.audioDuration + this.delayTime; } AudioManager.prototype = { constructor: AudioManager, /** * @param {Number} delta * @return {AudioManager} */ control: function control(delta) { this.elapsed += delta; this.currentTime += delta; if (this._shouldStopAudio()) this.audio.stop(); if (this._shouldStartAudio()) this.audio.play(); return this; }, // private methods _shouldStartAudio: function _shouldStartAudio() { if (this.audio.isPlaying) return false; while (this.currentTime >= this.duration) { this.currentTime -= this.duration; } if (this.currentTime < this.delayTime) return false; // 'duration' can be bigger than 'audioDuration + delayTime' because of sync configuration if (this.currentTime - this.delayTime > this.audioDuration) return false; return true; }, _shouldStopAudio: function _shouldStopAudio() { return this.audio.isPlaying && this.currentTime >= this.duration; } }; /** * @param {THREE.SkinnedMesh} mesh * @param {Array<Object>} grants */ function GrantSolver(mesh, grants) { this.mesh = mesh; this.grants = grants || []; } GrantSolver.prototype = { constructor: GrantSolver, /** * @return {GrantSolver} */ update: function () { var quaternion = new THREE.Quaternion(); return function () { var bones = this.mesh.skeleton.bones; var grants = this.grants; for (var i = 0, il = grants.length; i < il; i++) { var grant = grants[i]; var bone = bones[grant.index]; var parentBone = bones[grant.parentIndex]; if (grant.isLocal) { // TODO: implement if (grant.affectPosition) {} // TODO: implement if (grant.affectRotation) {} } else { // TODO: implement if (grant.affectPosition) {} if (grant.affectRotation) { quaternion.set(0, 0, 0, 1); quaternion.slerp(parentBone.quaternion, grant.ratio); bone.quaternion.multiply(quaternion); } } } return this; }; }() }; return MMDAnimationHelper; }();