bytev-charts
Version:
基于echarts和JavaScript及ES6封装的一个可以直接调用的图表组件库,内置主题设计,简单快捷,且支持用户自定义配置; npm 安装方式: npm install bytev-charts 若启动提示还需额外install插件,则运行 npm install @babel/runtime-corejs2 即可;
1,762 lines (1,392 loc) • 87.7 kB
JavaScript
import "core-js/modules/es.regexp.exec.js";
import "core-js/modules/es.string.split.js";
import "core-js/modules/es.string.trim.js";
import "core-js/modules/es.array.index-of.js";
import "core-js/modules/es.string.replace.js";
import "core-js/modules/es.array.sort.js";
import "core-js/modules/es.function.name.js";
import "core-js/modules/es.array.slice.js";
import "core-js/modules/es.array.last-index-of.js";
import "core-js/modules/es.string.repeat.js";
import "core-js/modules/es.array.map.js";
import "core-js/modules/es.function.bind.js";
import _Object$assign from "@babel/runtime-corejs2/core-js/object/assign";
import _Object$create from "@babel/runtime-corejs2/core-js/object/create";
import _parseFloat from "@babel/runtime-corejs2/core-js/parse-float";
import _parseInt from "@babel/runtime-corejs2/core-js/parse-int";
import _Object$keys from "@babel/runtime-corejs2/core-js/object/keys";
console.warn("THREE.ColladaLoader: 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.");
THREE.ColladaLoader = function (manager) {
THREE.Loader.call(this, manager);
};
THREE.ColladaLoader.prototype = _Object$assign(_Object$create(THREE.Loader.prototype), {
constructor: THREE.ColladaLoader,
load: function load(url, onLoad, onProgress, onError) {
var scope = this;
var path = scope.path === '' ? THREE.LoaderUtils.extractUrlBase(url) : scope.path;
var loader = new THREE.FileLoader(scope.manager);
loader.setPath(scope.path);
loader.setRequestHeader(scope.requestHeader);
loader.load(url, function (text) {
try {
onLoad(scope.parse(text, path));
} catch (e) {
if (onError) {
onError(e);
} else {
console.error(e);
}
scope.manager.itemError(url);
}
}, onProgress, onError);
},
options: {
set convertUpAxis(value) {
console.warn('THREE.ColladaLoader: options.convertUpAxis() has been removed. Up axis is converted automatically.');
}
},
parse: function parse(text, path) {
function getElementsByTagName(xml, name) {
// Non recursive xml.getElementsByTagName() ...
var array = [];
var childNodes = xml.childNodes;
for (var i = 0, l = childNodes.length; i < l; i++) {
var child = childNodes[i];
if (child.nodeName === name) {
array.push(child);
}
}
return array;
}
function parseStrings(text) {
if (text.length === 0) return [];
var parts = text.trim().split(/\s+/);
var array = new Array(parts.length);
for (var i = 0, l = parts.length; i < l; i++) {
array[i] = parts[i];
}
return array;
}
function parseFloats(text) {
if (text.length === 0) return [];
var parts = text.trim().split(/\s+/);
var array = new Array(parts.length);
for (var i = 0, l = parts.length; i < l; i++) {
array[i] = _parseFloat(parts[i]);
}
return array;
}
function parseInts(text) {
if (text.length === 0) return [];
var parts = text.trim().split(/\s+/);
var array = new Array(parts.length);
for (var i = 0, l = parts.length; i < l; i++) {
array[i] = _parseInt(parts[i]);
}
return array;
}
function parseId(text) {
return text.substring(1);
}
function generateId() {
return 'three_default_' + count++;
}
function isEmpty(object) {
return _Object$keys(object).length === 0;
} // asset
function parseAsset(xml) {
return {
unit: parseAssetUnit(getElementsByTagName(xml, 'unit')[0]),
upAxis: parseAssetUpAxis(getElementsByTagName(xml, 'up_axis')[0])
};
}
function parseAssetUnit(xml) {
if (xml !== undefined && xml.hasAttribute('meter') === true) {
return _parseFloat(xml.getAttribute('meter'));
} else {
return 1; // default 1 meter
}
}
function parseAssetUpAxis(xml) {
return xml !== undefined ? xml.textContent : 'Y_UP';
} // library
function parseLibrary(xml, libraryName, nodeName, parser) {
var library = getElementsByTagName(xml, libraryName)[0];
if (library !== undefined) {
var elements = getElementsByTagName(library, nodeName);
for (var i = 0; i < elements.length; i++) {
parser(elements[i]);
}
}
}
function buildLibrary(data, builder) {
for (var name in data) {
var object = data[name];
object.build = builder(data[name]);
}
} // get
function getBuild(data, builder) {
if (data.build !== undefined) return data.build;
data.build = builder(data);
return data.build;
} // animation
function parseAnimation(xml) {
var data = {
sources: {},
samplers: {},
channels: {}
};
var hasChildren = false;
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
var id;
switch (child.nodeName) {
case 'source':
id = child.getAttribute('id');
data.sources[id] = parseSource(child);
break;
case 'sampler':
id = child.getAttribute('id');
data.samplers[id] = parseAnimationSampler(child);
break;
case 'channel':
id = child.getAttribute('target');
data.channels[id] = parseAnimationChannel(child);
break;
case 'animation':
// hierarchy of related animations
parseAnimation(child);
hasChildren = true;
break;
default:
console.log(child);
}
}
if (hasChildren === false) {
// since 'id' attributes can be optional, it's necessary to generate a UUID for unqiue assignment
library.animations[xml.getAttribute('id') || THREE.MathUtils.generateUUID()] = data;
}
}
function parseAnimationSampler(xml) {
var data = {
inputs: {}
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'input':
var id = parseId(child.getAttribute('source'));
var semantic = child.getAttribute('semantic');
data.inputs[semantic] = id;
break;
}
}
return data;
}
function parseAnimationChannel(xml) {
var data = {};
var target = xml.getAttribute('target'); // parsing SID Addressing Syntax
var parts = target.split('/');
var id = parts.shift();
var sid = parts.shift(); // check selection syntax
var arraySyntax = sid.indexOf('(') !== -1;
var memberSyntax = sid.indexOf('.') !== -1;
if (memberSyntax) {
// member selection access
parts = sid.split('.');
sid = parts.shift();
data.member = parts.shift();
} else if (arraySyntax) {
// array-access syntax. can be used to express fields in one-dimensional vectors or two-dimensional matrices.
var indices = sid.split('(');
sid = indices.shift();
for (var i = 0; i < indices.length; i++) {
indices[i] = _parseInt(indices[i].replace(/\)/, ''));
}
data.indices = indices;
}
data.id = id;
data.sid = sid;
data.arraySyntax = arraySyntax;
data.memberSyntax = memberSyntax;
data.sampler = parseId(xml.getAttribute('source'));
return data;
}
function buildAnimation(data) {
var tracks = [];
var channels = data.channels;
var samplers = data.samplers;
var sources = data.sources;
for (var target in channels) {
if (channels.hasOwnProperty(target)) {
var channel = channels[target];
var sampler = samplers[channel.sampler];
var inputId = sampler.inputs.INPUT;
var outputId = sampler.inputs.OUTPUT;
var inputSource = sources[inputId];
var outputSource = sources[outputId];
var animation = buildAnimationChannel(channel, inputSource, outputSource);
createKeyframeTracks(animation, tracks);
}
}
return tracks;
}
function getAnimation(id) {
return getBuild(library.animations[id], buildAnimation);
}
function buildAnimationChannel(channel, inputSource, outputSource) {
var node = library.nodes[channel.id];
var object3D = getNode(node.id);
var transform = node.transforms[channel.sid];
var defaultMatrix = node.matrix.clone().transpose();
var time, stride;
var i, il, j, jl;
var data = {}; // the collada spec allows the animation of data in various ways.
// depending on the transform type (matrix, translate, rotate, scale), we execute different logic
switch (transform) {
case 'matrix':
for (i = 0, il = inputSource.array.length; i < il; i++) {
time = inputSource.array[i];
stride = i * outputSource.stride;
if (data[time] === undefined) data[time] = {};
if (channel.arraySyntax === true) {
var value = outputSource.array[stride];
var index = channel.indices[0] + 4 * channel.indices[1];
data[time][index] = value;
} else {
for (j = 0, jl = outputSource.stride; j < jl; j++) {
data[time][j] = outputSource.array[stride + j];
}
}
}
break;
case 'translate':
console.warn('THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform);
break;
case 'rotate':
console.warn('THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform);
break;
case 'scale':
console.warn('THREE.ColladaLoader: Animation transform type "%s" not yet implemented.', transform);
break;
}
var keyframes = prepareAnimationData(data, defaultMatrix);
var animation = {
name: object3D.uuid,
keyframes: keyframes
};
return animation;
}
function prepareAnimationData(data, defaultMatrix) {
var keyframes = []; // transfer data into a sortable array
for (var time in data) {
keyframes.push({
time: _parseFloat(time),
value: data[time]
});
} // ensure keyframes are sorted by time
keyframes.sort(ascending); // now we clean up all animation data, so we can use them for keyframe tracks
for (var i = 0; i < 16; i++) {
transformAnimationData(keyframes, i, defaultMatrix.elements[i]);
}
return keyframes; // array sort function
function ascending(a, b) {
return a.time - b.time;
}
}
var position = new THREE.Vector3();
var scale = new THREE.Vector3();
var quaternion = new THREE.Quaternion();
function createKeyframeTracks(animation, tracks) {
var keyframes = animation.keyframes;
var name = animation.name;
var times = [];
var positionData = [];
var quaternionData = [];
var scaleData = [];
for (var i = 0, l = keyframes.length; i < l; i++) {
var keyframe = keyframes[i];
var time = keyframe.time;
var value = keyframe.value;
matrix.fromArray(value).transpose();
matrix.decompose(position, quaternion, scale);
times.push(time);
positionData.push(position.x, position.y, position.z);
quaternionData.push(quaternion.x, quaternion.y, quaternion.z, quaternion.w);
scaleData.push(scale.x, scale.y, scale.z);
}
if (positionData.length > 0) tracks.push(new THREE.VectorKeyframeTrack(name + '.position', times, positionData));
if (quaternionData.length > 0) tracks.push(new THREE.QuaternionKeyframeTrack(name + '.quaternion', times, quaternionData));
if (scaleData.length > 0) tracks.push(new THREE.VectorKeyframeTrack(name + '.scale', times, scaleData));
return tracks;
}
function transformAnimationData(keyframes, property, defaultValue) {
var keyframe;
var empty = true;
var i, l; // check, if values of a property are missing in our keyframes
for (i = 0, l = keyframes.length; i < l; i++) {
keyframe = keyframes[i];
if (keyframe.value[property] === undefined) {
keyframe.value[property] = null; // mark as missing
} else {
empty = false;
}
}
if (empty === true) {
// no values at all, so we set a default value
for (i = 0, l = keyframes.length; i < l; i++) {
keyframe = keyframes[i];
keyframe.value[property] = defaultValue;
}
} else {
// filling gaps
createMissingKeyframes(keyframes, property);
}
}
function createMissingKeyframes(keyframes, property) {
var prev, next;
for (var i = 0, l = keyframes.length; i < l; i++) {
var keyframe = keyframes[i];
if (keyframe.value[property] === null) {
prev = getPrev(keyframes, i, property);
next = getNext(keyframes, i, property);
if (prev === null) {
keyframe.value[property] = next.value[property];
continue;
}
if (next === null) {
keyframe.value[property] = prev.value[property];
continue;
}
interpolate(keyframe, prev, next, property);
}
}
}
function getPrev(keyframes, i, property) {
while (i >= 0) {
var keyframe = keyframes[i];
if (keyframe.value[property] !== null) return keyframe;
i--;
}
return null;
}
function getNext(keyframes, i, property) {
while (i < keyframes.length) {
var keyframe = keyframes[i];
if (keyframe.value[property] !== null) return keyframe;
i++;
}
return null;
}
function interpolate(key, prev, next, property) {
if (next.time - prev.time === 0) {
key.value[property] = prev.value[property];
return;
}
key.value[property] = (key.time - prev.time) * (next.value[property] - prev.value[property]) / (next.time - prev.time) + prev.value[property];
} // animation clips
function parseAnimationClip(xml) {
var data = {
name: xml.getAttribute('id') || 'default',
start: _parseFloat(xml.getAttribute('start') || 0),
end: _parseFloat(xml.getAttribute('end') || 0),
animations: []
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'instance_animation':
data.animations.push(parseId(child.getAttribute('url')));
break;
}
}
library.clips[xml.getAttribute('id')] = data;
}
function buildAnimationClip(data) {
var tracks = [];
var name = data.name;
var duration = data.end - data.start || -1;
var animations = data.animations;
for (var i = 0, il = animations.length; i < il; i++) {
var animationTracks = getAnimation(animations[i]);
for (var j = 0, jl = animationTracks.length; j < jl; j++) {
tracks.push(animationTracks[j]);
}
}
return new THREE.AnimationClip(name, duration, tracks);
}
function getAnimationClip(id) {
return getBuild(library.clips[id], buildAnimationClip);
} // controller
function parseController(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'skin':
// there is exactly one skin per controller
data.id = parseId(child.getAttribute('source'));
data.skin = parseSkin(child);
break;
case 'morph':
data.id = parseId(child.getAttribute('source'));
console.warn('THREE.ColladaLoader: Morph target animation not supported yet.');
break;
}
}
library.controllers[xml.getAttribute('id')] = data;
}
function parseSkin(xml) {
var data = {
sources: {}
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'bind_shape_matrix':
data.bindShapeMatrix = parseFloats(child.textContent);
break;
case 'source':
var id = child.getAttribute('id');
data.sources[id] = parseSource(child);
break;
case 'joints':
data.joints = parseJoints(child);
break;
case 'vertex_weights':
data.vertexWeights = parseVertexWeights(child);
break;
}
}
return data;
}
function parseJoints(xml) {
var data = {
inputs: {}
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'input':
var semantic = child.getAttribute('semantic');
var id = parseId(child.getAttribute('source'));
data.inputs[semantic] = id;
break;
}
}
return data;
}
function parseVertexWeights(xml) {
var data = {
inputs: {}
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'input':
var semantic = child.getAttribute('semantic');
var id = parseId(child.getAttribute('source'));
var offset = _parseInt(child.getAttribute('offset'));
data.inputs[semantic] = {
id: id,
offset: offset
};
break;
case 'vcount':
data.vcount = parseInts(child.textContent);
break;
case 'v':
data.v = parseInts(child.textContent);
break;
}
}
return data;
}
function buildController(data) {
var build = {
id: data.id
};
var geometry = library.geometries[build.id];
if (data.skin !== undefined) {
build.skin = buildSkin(data.skin); // we enhance the 'sources' property of the corresponding geometry with our skin data
geometry.sources.skinIndices = build.skin.indices;
geometry.sources.skinWeights = build.skin.weights;
}
return build;
}
function buildSkin(data) {
var BONE_LIMIT = 4;
var build = {
joints: [],
// this must be an array to preserve the joint order
indices: {
array: [],
stride: BONE_LIMIT
},
weights: {
array: [],
stride: BONE_LIMIT
}
};
var sources = data.sources;
var vertexWeights = data.vertexWeights;
var vcount = vertexWeights.vcount;
var v = vertexWeights.v;
var jointOffset = vertexWeights.inputs.JOINT.offset;
var weightOffset = vertexWeights.inputs.WEIGHT.offset;
var jointSource = data.sources[data.joints.inputs.JOINT];
var inverseSource = data.sources[data.joints.inputs.INV_BIND_MATRIX];
var weights = sources[vertexWeights.inputs.WEIGHT.id].array;
var stride = 0;
var i, j, l; // procces skin data for each vertex
for (i = 0, l = vcount.length; i < l; i++) {
var jointCount = vcount[i]; // this is the amount of joints that affect a single vertex
var vertexSkinData = [];
for (j = 0; j < jointCount; j++) {
var skinIndex = v[stride + jointOffset];
var weightId = v[stride + weightOffset];
var skinWeight = weights[weightId];
vertexSkinData.push({
index: skinIndex,
weight: skinWeight
});
stride += 2;
} // we sort the joints in descending order based on the weights.
// this ensures, we only procced the most important joints of the vertex
vertexSkinData.sort(descending); // now we provide for each vertex a set of four index and weight values.
// the order of the skin data matches the order of vertices
for (j = 0; j < BONE_LIMIT; j++) {
var d = vertexSkinData[j];
if (d !== undefined) {
build.indices.array.push(d.index);
build.weights.array.push(d.weight);
} else {
build.indices.array.push(0);
build.weights.array.push(0);
}
}
} // setup bind matrix
if (data.bindShapeMatrix) {
build.bindMatrix = new THREE.Matrix4().fromArray(data.bindShapeMatrix).transpose();
} else {
build.bindMatrix = new THREE.Matrix4().identity();
} // process bones and inverse bind matrix data
for (i = 0, l = jointSource.array.length; i < l; i++) {
var name = jointSource.array[i];
var boneInverse = new THREE.Matrix4().fromArray(inverseSource.array, i * inverseSource.stride).transpose();
build.joints.push({
name: name,
boneInverse: boneInverse
});
}
return build; // array sort function
function descending(a, b) {
return b.weight - a.weight;
}
}
function getController(id) {
return getBuild(library.controllers[id], buildController);
} // image
function parseImage(xml) {
var data = {
init_from: getElementsByTagName(xml, 'init_from')[0].textContent
};
library.images[xml.getAttribute('id')] = data;
}
function buildImage(data) {
if (data.build !== undefined) return data.build;
return data.init_from;
}
function getImage(id) {
var data = library.images[id];
if (data !== undefined) {
return getBuild(data, buildImage);
}
console.warn('THREE.ColladaLoader: Couldn\'t find image with ID:', id);
return null;
} // effect
function parseEffect(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'profile_COMMON':
data.profile = parseEffectProfileCOMMON(child);
break;
}
}
library.effects[xml.getAttribute('id')] = data;
}
function parseEffectProfileCOMMON(xml) {
var data = {
surfaces: {},
samplers: {}
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'newparam':
parseEffectNewparam(child, data);
break;
case 'technique':
data.technique = parseEffectTechnique(child);
break;
case 'extra':
data.extra = parseEffectExtra(child);
break;
}
}
return data;
}
function parseEffectNewparam(xml, data) {
var sid = xml.getAttribute('sid');
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'surface':
data.surfaces[sid] = parseEffectSurface(child);
break;
case 'sampler2D':
data.samplers[sid] = parseEffectSampler(child);
break;
}
}
}
function parseEffectSurface(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'init_from':
data.init_from = child.textContent;
break;
}
}
return data;
}
function parseEffectSampler(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'source':
data.source = child.textContent;
break;
}
}
return data;
}
function parseEffectTechnique(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'constant':
case 'lambert':
case 'blinn':
case 'phong':
data.type = child.nodeName;
data.parameters = parseEffectParameters(child);
break;
}
}
return data;
}
function parseEffectParameters(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'emission':
case 'diffuse':
case 'specular':
case 'bump':
case 'ambient':
case 'shininess':
case 'transparency':
data[child.nodeName] = parseEffectParameter(child);
break;
case 'transparent':
data[child.nodeName] = {
opaque: child.getAttribute('opaque'),
data: parseEffectParameter(child)
};
break;
}
}
return data;
}
function parseEffectParameter(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'color':
data[child.nodeName] = parseFloats(child.textContent);
break;
case 'float':
data[child.nodeName] = _parseFloat(child.textContent);
break;
case 'texture':
data[child.nodeName] = {
id: child.getAttribute('texture'),
extra: parseEffectParameterTexture(child)
};
break;
}
}
return data;
}
function parseEffectParameterTexture(xml) {
var data = {
technique: {}
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'extra':
parseEffectParameterTextureExtra(child, data);
break;
}
}
return data;
}
function parseEffectParameterTextureExtra(xml, data) {
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'technique':
parseEffectParameterTextureExtraTechnique(child, data);
break;
}
}
}
function parseEffectParameterTextureExtraTechnique(xml, data) {
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'repeatU':
case 'repeatV':
case 'offsetU':
case 'offsetV':
data.technique[child.nodeName] = _parseFloat(child.textContent);
break;
case 'wrapU':
case 'wrapV':
// some files have values for wrapU/wrapV which become NaN via parseInt
if (child.textContent.toUpperCase() === 'TRUE') {
data.technique[child.nodeName] = 1;
} else if (child.textContent.toUpperCase() === 'FALSE') {
data.technique[child.nodeName] = 0;
} else {
data.technique[child.nodeName] = _parseInt(child.textContent);
}
break;
}
}
}
function parseEffectExtra(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'technique':
data.technique = parseEffectExtraTechnique(child);
break;
}
}
return data;
}
function parseEffectExtraTechnique(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'double_sided':
data[child.nodeName] = _parseInt(child.textContent);
break;
}
}
return data;
}
function buildEffect(data) {
return data;
}
function getEffect(id) {
return getBuild(library.effects[id], buildEffect);
} // material
function parseMaterial(xml) {
var data = {
name: xml.getAttribute('name')
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'instance_effect':
data.url = parseId(child.getAttribute('url'));
break;
}
}
library.materials[xml.getAttribute('id')] = data;
}
function getTextureLoader(image) {
var loader;
var extension = image.slice((image.lastIndexOf('.') - 1 >>> 0) + 2); // http://www.jstips.co/en/javascript/get-file-extension/
extension = extension.toLowerCase();
switch (extension) {
case 'tga':
loader = tgaLoader;
break;
default:
loader = textureLoader;
}
return loader;
}
function buildMaterial(data) {
var effect = getEffect(data.url);
var technique = effect.profile.technique;
var extra = effect.profile.extra;
var material;
switch (technique.type) {
case 'phong':
case 'blinn':
material = new THREE.MeshPhongMaterial();
break;
case 'lambert':
material = new THREE.MeshLambertMaterial();
break;
default:
material = new THREE.MeshBasicMaterial();
break;
}
material.name = data.name || '';
function getTexture(textureObject) {
var sampler = effect.profile.samplers[textureObject.id];
var image = null; // get image
if (sampler !== undefined) {
var surface = effect.profile.surfaces[sampler.source];
image = getImage(surface.init_from);
} else {
console.warn('THREE.ColladaLoader: Undefined sampler. Access image directly (see #12530).');
image = getImage(textureObject.id);
} // create texture if image is avaiable
if (image !== null) {
var loader = getTextureLoader(image);
if (loader !== undefined) {
var texture = loader.load(image);
var extra = textureObject.extra;
if (extra !== undefined && extra.technique !== undefined && isEmpty(extra.technique) === false) {
var technique = extra.technique;
texture.wrapS = technique.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
texture.wrapT = technique.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
texture.offset.set(technique.offsetU || 0, technique.offsetV || 0);
texture.repeat.set(technique.repeatU || 1, technique.repeatV || 1);
} else {
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
}
return texture;
} else {
console.warn('THREE.ColladaLoader: Loader for texture %s not found.', image);
return null;
}
} else {
console.warn('THREE.ColladaLoader: Couldn\'t create texture with ID:', textureObject.id);
return null;
}
}
var parameters = technique.parameters;
for (var key in parameters) {
var parameter = parameters[key];
switch (key) {
case 'diffuse':
if (parameter.color) material.color.fromArray(parameter.color);
if (parameter.texture) material.map = getTexture(parameter.texture);
break;
case 'specular':
if (parameter.color && material.specular) material.specular.fromArray(parameter.color);
if (parameter.texture) material.specularMap = getTexture(parameter.texture);
break;
case 'bump':
if (parameter.texture) material.normalMap = getTexture(parameter.texture);
break;
case 'ambient':
if (parameter.texture) material.lightMap = getTexture(parameter.texture);
break;
case 'shininess':
if (parameter["float"] && material.shininess) material.shininess = parameter["float"];
break;
case 'emission':
if (parameter.color && material.emissive) material.emissive.fromArray(parameter.color);
if (parameter.texture) material.emissiveMap = getTexture(parameter.texture);
break;
}
} //
var transparent = parameters['transparent'];
var transparency = parameters['transparency']; // <transparency> does not exist but <transparent>
if (transparency === undefined && transparent) {
transparency = {
"float": 1
};
} // <transparent> does not exist but <transparency>
if (transparent === undefined && transparency) {
transparent = {
opaque: 'A_ONE',
data: {
color: [1, 1, 1, 1]
}
};
}
if (transparent && transparency) {
// handle case if a texture exists but no color
if (transparent.data.texture) {
// we do not set an alpha map (see #13792)
material.transparent = true;
} else {
var color = transparent.data.color;
switch (transparent.opaque) {
case 'A_ONE':
material.opacity = color[3] * transparency["float"];
break;
case 'RGB_ZERO':
material.opacity = 1 - color[0] * transparency["float"];
break;
case 'A_ZERO':
material.opacity = 1 - color[3] * transparency["float"];
break;
case 'RGB_ONE':
material.opacity = color[0] * transparency["float"];
break;
default:
console.warn('THREE.ColladaLoader: Invalid opaque type "%s" of transparent tag.', transparent.opaque);
}
if (material.opacity < 1) material.transparent = true;
}
} //
if (extra !== undefined && extra.technique !== undefined && extra.technique.double_sided === 1) {
material.side = THREE.DoubleSide;
}
return material;
}
function getMaterial(id) {
return getBuild(library.materials[id], buildMaterial);
} // camera
function parseCamera(xml) {
var data = {
name: xml.getAttribute('name')
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'optics':
data.optics = parseCameraOptics(child);
break;
}
}
library.cameras[xml.getAttribute('id')] = data;
}
function parseCameraOptics(xml) {
for (var i = 0; i < xml.childNodes.length; i++) {
var child = xml.childNodes[i];
switch (child.nodeName) {
case 'technique_common':
return parseCameraTechnique(child);
}
}
return {};
}
function parseCameraTechnique(xml) {
var data = {};
for (var i = 0; i < xml.childNodes.length; i++) {
var child = xml.childNodes[i];
switch (child.nodeName) {
case 'perspective':
case 'orthographic':
data.technique = child.nodeName;
data.parameters = parseCameraParameters(child);
break;
}
}
return data;
}
function parseCameraParameters(xml) {
var data = {};
for (var i = 0; i < xml.childNodes.length; i++) {
var child = xml.childNodes[i];
switch (child.nodeName) {
case 'xfov':
case 'yfov':
case 'xmag':
case 'ymag':
case 'znear':
case 'zfar':
case 'aspect_ratio':
data[child.nodeName] = _parseFloat(child.textContent);
break;
}
}
return data;
}
function buildCamera(data) {
var camera;
switch (data.optics.technique) {
case 'perspective':
camera = new THREE.PerspectiveCamera(data.optics.parameters.yfov, data.optics.parameters.aspect_ratio, data.optics.parameters.znear, data.optics.parameters.zfar);
break;
case 'orthographic':
var ymag = data.optics.parameters.ymag;
var xmag = data.optics.parameters.xmag;
var aspectRatio = data.optics.parameters.aspect_ratio;
xmag = xmag === undefined ? ymag * aspectRatio : xmag;
ymag = ymag === undefined ? xmag / aspectRatio : ymag;
xmag *= 0.5;
ymag *= 0.5;
camera = new THREE.OrthographicCamera(-xmag, xmag, ymag, -ymag, // left, right, top, bottom
data.optics.parameters.znear, data.optics.parameters.zfar);
break;
default:
camera = new THREE.PerspectiveCamera();
break;
}
camera.name = data.name || '';
return camera;
}
function getCamera(id) {
var data = library.cameras[id];
if (data !== undefined) {
return getBuild(data, buildCamera);
}
console.warn('THREE.ColladaLoader: Couldn\'t find camera with ID:', id);
return null;
} // light
function parseLight(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'technique_common':
data = parseLightTechnique(child);
break;
}
}
library.lights[xml.getAttribute('id')] = data;
}
function parseLightTechnique(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'directional':
case 'point':
case 'spot':
case 'ambient':
data.technique = child.nodeName;
data.parameters = parseLightParameters(child);
}
}
return data;
}
function parseLightParameters(xml) {
var data = {};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'color':
var array = parseFloats(child.textContent);
data.color = new THREE.Color().fromArray(array);
break;
case 'falloff_angle':
data.falloffAngle = _parseFloat(child.textContent);
break;
case 'quadratic_attenuation':
var f = _parseFloat(child.textContent);
data.distance = f ? Math.sqrt(1 / f) : 0;
break;
}
}
return data;
}
function buildLight(data) {
var light;
switch (data.technique) {
case 'directional':
light = new THREE.DirectionalLight();
break;
case 'point':
light = new THREE.PointLight();
break;
case 'spot':
light = new THREE.SpotLight();
break;
case 'ambient':
light = new THREE.AmbientLight();
break;
}
if (data.parameters.color) light.color.copy(data.parameters.color);
if (data.parameters.distance) light.distance = data.parameters.distance;
return light;
}
function getLight(id) {
var data = library.lights[id];
if (data !== undefined) {
return getBuild(data, buildLight);
}
console.warn('THREE.ColladaLoader: Couldn\'t find light with ID:', id);
return null;
} // geometry
function parseGeometry(xml) {
var data = {
name: xml.getAttribute('name'),
sources: {},
vertices: {},
primitives: []
};
var mesh = getElementsByTagName(xml, 'mesh')[0]; // the following tags inside geometry are not supported yet (see https://github.com/mrdoob/three.js/pull/12606): convex_mesh, spline, brep
if (mesh === undefined) return;
for (var i = 0; i < mesh.childNodes.length; i++) {
var child = mesh.childNodes[i];
if (child.nodeType !== 1) continue;
var id = child.getAttribute('id');
switch (child.nodeName) {
case 'source':
data.sources[id] = parseSource(child);
break;
case 'vertices':
// data.sources[ id ] = data.sources[ parseId( getElementsByTagName( child, 'input' )[ 0 ].getAttribute( 'source' ) ) ];
data.vertices = parseGeometryVertices(child);
break;
case 'polygons':
console.warn('THREE.ColladaLoader: Unsupported primitive type: ', child.nodeName);
break;
case 'lines':
case 'linestrips':
case 'polylist':
case 'triangles':
data.primitives.push(parseGeometryPrimitive(child));
break;
default:
console.log(child);
}
}
library.geometries[xml.getAttribute('id')] = data;
}
function parseSource(xml) {
var data = {
array: [],
stride: 3
};
for (var i = 0; i < xml.childNodes.length; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'float_array':
data.array = parseFloats(child.textContent);
break;
case 'Name_array':
data.array = parseStrings(child.textContent);
break;
case 'technique_common':
var accessor = getElementsByTagName(child, 'accessor')[0];
if (accessor !== undefined) {
data.stride = _parseInt(accessor.getAttribute('stride'));
}
break;
}
}
return data;
}
function parseGeometryVertices(xml) {
var data = {};
for (var i = 0; i < xml.childNodes.length; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
data[child.getAttribute('semantic')] = parseId(child.getAttribute('source'));
}
return data;
}
function parseGeometryPrimitive(xml) {
var primitive = {
type: xml.nodeName,
material: xml.getAttribute('material'),
count: _parseInt(xml.getAttribute('count')),
inputs: {},
stride: 0,
hasUV: false
};
for (var i = 0, l = xml.childNodes.length; i < l; i++) {
var child = xml.childNodes[i];
if (child.nodeType !== 1) continue;
switch (child.nodeName) {
case 'input':
var id = parseId(child.getAttribute('source'));
var semantic = child.getAttribute('semantic');
var offset = _parseInt(child.getAttribute('offset'));
var set = _parseInt(child.getAttribute('set'));
var inputname = set > 0 ? semantic + set : semantic;
primitive.inputs[inputname] = {
id: id,
offset: offset
};
primitive.stride = Math.max(primitive.stride, offset + 1);
if (semantic === 'TEXCOORD') primitive.hasUV = true;
break;
case 'vcount':
primitive.vcount = parseInts(child.textContent);
break;
case 'p':
primitive.p = parseInts(child.textContent);
break;
}
}
return primitive;
}
function groupPrimitives(primitives) {
var build = {};
for (var i = 0; i < primitives.length; i++) {
var primitive = primitives[i];
if (build[primitive.type] === undefined) build[primitive.type] = [];
build[primitive.type].push(primitive);
}
return build;
}
function checkUVCoordinates(primitives) {
var count = 0;
for (var i = 0, l = primitives.length; i < l; i++) {
var primitive = primitives[i];
if (primitive.hasUV === true) {
count++;
}
}
if (count > 0 && count < primitives.length) {
primitives.uvsNeedsFix = true;
}
}
function buildGeometry(data) {
var build = {};
var sources = data.sources;
var vertices = data.vertices;
var primitives = data.primitives;
if (primitives.length === 0) return {}; // our goal is to create one buffer geometry for a single type of primitives
// first, we group all primitives by their type
var groupedPrimitives = groupPrimitives(primitives);
for (var type in groupedPrimitives) {
var primitiveType = groupedPrimitives[type]; // second, ensure consistent uv coordinates for each type of primitives (polylist,triangles or lines)
checkUVCoordinates(primitiveType); // third, create a buffer geometry for each type of primitives
build[type] = buildGeometryType(primitiveType, sources, vertices);
}
return build;
}
function buildGeometryType(primitives, sources, vertices) {
var build = {};
var position = {
array: [],
stride: 0
};
var normal = {
array: [],
stride: 0
};
var uv = {
array: [],
stride: 0
};
var uv2 = {
array: [],
stride: 0
};
var color = {
array: [],
stride: 0
};
var skinIndex = {
array: [],
stride: 4
};
var skinWeight = {
array: [],
stride: 4
};
var geometry = new THREE.BufferGeometry();
var materialKeys = [];
var start = 0;
for (var p = 0; p < primitives.length; p++) {
var primitive = primitives[p];
var inputs = primitive.inputs; // groups
var count = 0;
switch (primitive.type) {
case 'lines':
case 'linestrips':
count = primitive.count * 2;
break;
case 'triangles':
count = primitive.count * 3;
break;
case 'polylist':
for (var g = 0; g < primitive.count; g++) {
var vc = primitive.vcount[g];
switch (vc) {
case 3:
count += 3; // single triangle
break;
case 4:
count += 6; // quad, subdivided into two triangles
break;
default:
count += (vc - 2) * 3; // polylist with more than four vertices
break;
}
}
break;
default:
console.warn('THREE.ColladaLoader: Unknow primitive type:', primitive.type);
}
geometry.addGroup(start, count, p);
start += count; // material
if (primitive.material) {
materialKeys.push(primitive.material);
} // geometry data
for (var name in inputs) {
var input = inputs[name];
switch (name) {
case 'VERTEX':
for (var key in vertices) {
var id = vertices[key];
switch (key) {
case 'POSITION':
var prevLength = position.array.length;
buildGeometryData(primitive, sources[id], input.offset, position.array);
position.stride = sources[id].stride;
if (sources.skinWeights && sources.skinIndices) {
buildGeometryData(primitive, sources.skinIndices, input.offset, skinIndex.array);
buildGeometryData(primitive, sources.skinWeights, input.offset, skinWeight.array);
} // see #3803
if (primitive.hasUV === false && primitives.uvsNeedsFix === true) {
var count = (position.array.length - prevLength) / position.stride;
for (var i = 0; i < count; i++) {
// fill missing uv coordinates
uv.array.push(0, 0);