提交
This commit is contained in:
BIN
example/js/6520.pbf
Normal file
BIN
example/js/6520.pbf
Normal file
Binary file not shown.
BIN
example/js/94.pbf
Normal file
BIN
example/js/94.pbf
Normal file
Binary file not shown.
990
example/js/libgif.js
Normal file
990
example/js/libgif.js
Normal file
@ -0,0 +1,990 @@
|
||||
/*
|
||||
SuperGif
|
||||
|
||||
Example usage:
|
||||
|
||||
<img src="./example1_preview.gif" rel:animated_src="./example1.gif" width="360" height="360" rel:auto_play="1" />
|
||||
|
||||
<script type="text/javascript">
|
||||
$$('img').each(function (img_tag) {
|
||||
if (/.*\.gif/.test(img_tag.src)) {
|
||||
var rub = new SuperGif({ gif: img_tag } );
|
||||
rub.load();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
Image tag attributes:
|
||||
|
||||
rel:animated_src - If this url is specified, it's loaded into the player instead of src.
|
||||
This allows a preview frame to be shown until animated gif data is streamed into the canvas
|
||||
|
||||
rel:auto_play - Defaults to 1 if not specified. If set to zero, a call to the play() method is needed
|
||||
|
||||
Constructor options args
|
||||
|
||||
gif Required. The DOM element of an img tag.
|
||||
loop_mode Optional. Setting this to false will force disable looping of the gif.
|
||||
auto_play Optional. Same as the rel:auto_play attribute above, this arg overrides the img tag info.
|
||||
max_width Optional. Scale images over max_width down to max_width. Helpful with mobile.
|
||||
on_end Optional. Add a callback for when the gif reaches the end of a single loop (one iteration). The first argument passed will be the gif HTMLElement.
|
||||
loop_delay Optional. The amount of time to pause (in ms) after each single loop (iteration).
|
||||
draw_while_loading Optional. Determines whether the gif will be drawn to the canvas whilst it is loaded.
|
||||
show_progress_bar Optional. Only applies when draw_while_loading is set to true.
|
||||
|
||||
Instance methods
|
||||
|
||||
// loading
|
||||
load( callback ) Loads the gif specified by the src or rel:animated_src sttributie of the img tag into a canvas element and then calls callback if one is passed
|
||||
load_url( src, callback ) Loads the gif file specified in the src argument into a canvas element and then calls callback if one is passed
|
||||
|
||||
// play controls
|
||||
play - Start playing the gif
|
||||
pause - Stop playing the gif
|
||||
move_to(i) - Move to frame i of the gif
|
||||
move_relative(i) - Move i frames ahead (or behind if i < 0)
|
||||
|
||||
// getters
|
||||
get_canvas The canvas element that the gif is playing in. Handy for assigning event handlers to.
|
||||
get_playing Whether or not the gif is currently playing
|
||||
get_loading Whether or not the gif has finished loading/parsing
|
||||
get_auto_play Whether or not the gif is set to play automatically
|
||||
get_length The number of frames in the gif
|
||||
get_current_frame The index of the currently displayed frame of the gif
|
||||
|
||||
For additional customization (viewport inside iframe) these params may be passed:
|
||||
c_w, c_h - width and height of canvas
|
||||
vp_t, vp_l, vp_ w, vp_h - top, left, width and height of the viewport
|
||||
|
||||
A bonus: few articles to understand what is going on
|
||||
http://enthusiasms.org/post/16976438906
|
||||
http://www.matthewflickinger.com/lab/whatsinagif/bits_and_bytes.asp
|
||||
http://humpy77.deviantart.com/journal/Frame-Delay-Times-for-Animated-GIFs-214150546
|
||||
|
||||
*/
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
define([], factory);
|
||||
} else if (typeof exports === 'object') {
|
||||
module.exports = factory();
|
||||
} else {
|
||||
root.SuperGif = factory();
|
||||
}
|
||||
}(this, function () {
|
||||
// Generic functions
|
||||
var bitsToNum = function (ba) {
|
||||
return ba.reduce(function (s, n) {
|
||||
return s * 2 + n;
|
||||
}, 0);
|
||||
};
|
||||
|
||||
var byteToBitArr = function (bite) {
|
||||
var a = [];
|
||||
for (var i = 7; i >= 0; i--) {
|
||||
a.push( !! (bite & (1 << i)));
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
// Stream
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
// Make compiler happy.
|
||||
var Stream = function (data) {
|
||||
this.data = data;
|
||||
this.len = this.data.length;
|
||||
this.pos = 0;
|
||||
|
||||
this.readByte = function () {
|
||||
if (this.pos >= this.data.length) {
|
||||
throw new Error('Attempted to read past end of stream.');
|
||||
}
|
||||
if (data instanceof Uint8Array)
|
||||
return data[this.pos++];
|
||||
else
|
||||
return data.charCodeAt(this.pos++) & 0xFF;
|
||||
};
|
||||
|
||||
this.readBytes = function (n) {
|
||||
var bytes = [];
|
||||
for (var i = 0; i < n; i++) {
|
||||
bytes.push(this.readByte());
|
||||
}
|
||||
return bytes;
|
||||
};
|
||||
|
||||
this.read = function (n) {
|
||||
var s = '';
|
||||
for (var i = 0; i < n; i++) {
|
||||
s += String.fromCharCode(this.readByte());
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
this.readUnsigned = function () { // Little-endian.
|
||||
var a = this.readBytes(2);
|
||||
return (a[1] << 8) + a[0];
|
||||
};
|
||||
};
|
||||
|
||||
var lzwDecode = function (minCodeSize, data) {
|
||||
// TODO: Now that the GIF parser is a bit different, maybe this should get an array of bytes instead of a String?
|
||||
var pos = 0; // Maybe this streaming thing should be merged with the Stream?
|
||||
var readCode = function (size) {
|
||||
var code = 0;
|
||||
for (var i = 0; i < size; i++) {
|
||||
if (data.charCodeAt(pos >> 3) & (1 << (pos & 7))) {
|
||||
code |= 1 << i;
|
||||
}
|
||||
pos++;
|
||||
}
|
||||
return code;
|
||||
};
|
||||
|
||||
var output = [];
|
||||
|
||||
var clearCode = 1 << minCodeSize;
|
||||
var eoiCode = clearCode + 1;
|
||||
|
||||
var codeSize = minCodeSize + 1;
|
||||
|
||||
var dict = [];
|
||||
|
||||
var clear = function () {
|
||||
dict = [];
|
||||
codeSize = minCodeSize + 1;
|
||||
for (var i = 0; i < clearCode; i++) {
|
||||
dict[i] = [i];
|
||||
}
|
||||
dict[clearCode] = [];
|
||||
dict[eoiCode] = null;
|
||||
|
||||
};
|
||||
|
||||
var code;
|
||||
var last;
|
||||
|
||||
while (true) {
|
||||
last = code;
|
||||
code = readCode(codeSize);
|
||||
|
||||
if (code === clearCode) {
|
||||
clear();
|
||||
continue;
|
||||
}
|
||||
if (code === eoiCode) break;
|
||||
|
||||
if (code < dict.length) {
|
||||
if (last !== clearCode) {
|
||||
dict.push(dict[last].concat(dict[code][0]));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (code !== dict.length) throw new Error('Invalid LZW code.');
|
||||
dict.push(dict[last].concat(dict[last][0]));
|
||||
}
|
||||
output.push.apply(output, dict[code]);
|
||||
|
||||
if (dict.length === (1 << codeSize) && codeSize < 12) {
|
||||
// If we're at the last code and codeSize is 12, the next code will be a clearCode, and it'll be 12 bits long.
|
||||
codeSize++;
|
||||
}
|
||||
}
|
||||
|
||||
// I don't know if this is technically an error, but some GIFs do it.
|
||||
//if (Math.ceil(pos / 8) !== data.length) throw new Error('Extraneous LZW bytes.');
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
// The actual parsing; returns an object with properties.
|
||||
var parseGIF = function (st, handler) {
|
||||
handler || (handler = {});
|
||||
|
||||
// LZW (GIF-specific)
|
||||
var parseCT = function (entries) { // Each entry is 3 bytes, for RGB.
|
||||
var ct = [];
|
||||
for (var i = 0; i < entries; i++) {
|
||||
ct.push(st.readBytes(3));
|
||||
}
|
||||
return ct;
|
||||
};
|
||||
|
||||
var readSubBlocks = function () {
|
||||
var size, data;
|
||||
data = '';
|
||||
do {
|
||||
size = st.readByte();
|
||||
data += st.read(size);
|
||||
} while (size !== 0);
|
||||
return data;
|
||||
};
|
||||
|
||||
var parseHeader = function () {
|
||||
var hdr = {};
|
||||
hdr.sig = st.read(3);
|
||||
hdr.ver = st.read(3);
|
||||
if (hdr.sig !== 'GIF') throw new Error('Not a GIF file.'); // XXX: This should probably be handled more nicely.
|
||||
hdr.width = st.readUnsigned();
|
||||
hdr.height = st.readUnsigned();
|
||||
|
||||
var bits = byteToBitArr(st.readByte());
|
||||
hdr.gctFlag = bits.shift();
|
||||
hdr.colorRes = bitsToNum(bits.splice(0, 3));
|
||||
hdr.sorted = bits.shift();
|
||||
hdr.gctSize = bitsToNum(bits.splice(0, 3));
|
||||
|
||||
hdr.bgColor = st.readByte();
|
||||
hdr.pixelAspectRatio = st.readByte(); // if not 0, aspectRatio = (pixelAspectRatio + 15) / 64
|
||||
if (hdr.gctFlag) {
|
||||
hdr.gct = parseCT(1 << (hdr.gctSize + 1));
|
||||
}
|
||||
handler.hdr && handler.hdr(hdr);
|
||||
};
|
||||
|
||||
var parseExt = function (block) {
|
||||
var parseGCExt = function (block) {
|
||||
var blockSize = st.readByte(); // Always 4
|
||||
var bits = byteToBitArr(st.readByte());
|
||||
block.reserved = bits.splice(0, 3); // Reserved; should be 000.
|
||||
block.disposalMethod = bitsToNum(bits.splice(0, 3));
|
||||
block.userInput = bits.shift();
|
||||
block.transparencyGiven = bits.shift();
|
||||
|
||||
block.delayTime = st.readUnsigned();
|
||||
|
||||
block.transparencyIndex = st.readByte();
|
||||
|
||||
block.terminator = st.readByte();
|
||||
|
||||
handler.gce && handler.gce(block);
|
||||
};
|
||||
|
||||
var parseComExt = function (block) {
|
||||
block.comment = readSubBlocks();
|
||||
handler.com && handler.com(block);
|
||||
};
|
||||
|
||||
var parsePTExt = function (block) {
|
||||
// No one *ever* uses this. If you use it, deal with parsing it yourself.
|
||||
var blockSize = st.readByte(); // Always 12
|
||||
block.ptHeader = st.readBytes(12);
|
||||
block.ptData = readSubBlocks();
|
||||
handler.pte && handler.pte(block);
|
||||
};
|
||||
|
||||
var parseAppExt = function (block) {
|
||||
var parseNetscapeExt = function (block) {
|
||||
var blockSize = st.readByte(); // Always 3
|
||||
block.unknown = st.readByte(); // ??? Always 1? What is this?
|
||||
block.iterations = st.readUnsigned();
|
||||
block.terminator = st.readByte();
|
||||
handler.app && handler.app.NETSCAPE && handler.app.NETSCAPE(block);
|
||||
};
|
||||
|
||||
var parseUnknownAppExt = function (block) {
|
||||
block.appData = readSubBlocks();
|
||||
// FIXME: This won't work if a handler wants to match on any identifier.
|
||||
handler.app && handler.app[block.identifier] && handler.app[block.identifier](block);
|
||||
};
|
||||
|
||||
var blockSize = st.readByte(); // Always 11
|
||||
block.identifier = st.read(8);
|
||||
block.authCode = st.read(3);
|
||||
switch (block.identifier) {
|
||||
case 'NETSCAPE':
|
||||
parseNetscapeExt(block);
|
||||
break;
|
||||
default:
|
||||
parseUnknownAppExt(block);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
var parseUnknownExt = function (block) {
|
||||
block.data = readSubBlocks();
|
||||
handler.unknown && handler.unknown(block);
|
||||
};
|
||||
|
||||
block.label = st.readByte();
|
||||
switch (block.label) {
|
||||
case 0xF9:
|
||||
block.extType = 'gce';
|
||||
parseGCExt(block);
|
||||
break;
|
||||
case 0xFE:
|
||||
block.extType = 'com';
|
||||
parseComExt(block);
|
||||
break;
|
||||
case 0x01:
|
||||
block.extType = 'pte';
|
||||
parsePTExt(block);
|
||||
break;
|
||||
case 0xFF:
|
||||
block.extType = 'app';
|
||||
parseAppExt(block);
|
||||
break;
|
||||
default:
|
||||
block.extType = 'unknown';
|
||||
parseUnknownExt(block);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
var parseImg = function (img) {
|
||||
var deinterlace = function (pixels, width) {
|
||||
// Of course this defeats the purpose of interlacing. And it's *probably*
|
||||
// the least efficient way it's ever been implemented. But nevertheless...
|
||||
var newPixels = new Array(pixels.length);
|
||||
var rows = pixels.length / width;
|
||||
var cpRow = function (toRow, fromRow) {
|
||||
var fromPixels = pixels.slice(fromRow * width, (fromRow + 1) * width);
|
||||
newPixels.splice.apply(newPixels, [toRow * width, width].concat(fromPixels));
|
||||
};
|
||||
|
||||
// See appendix E.
|
||||
var offsets = [0, 4, 2, 1];
|
||||
var steps = [8, 8, 4, 2];
|
||||
|
||||
var fromRow = 0;
|
||||
for (var pass = 0; pass < 4; pass++) {
|
||||
for (var toRow = offsets[pass]; toRow < rows; toRow += steps[pass]) {
|
||||
cpRow(toRow, fromRow)
|
||||
fromRow++;
|
||||
}
|
||||
}
|
||||
|
||||
return newPixels;
|
||||
};
|
||||
|
||||
img.leftPos = st.readUnsigned();
|
||||
img.topPos = st.readUnsigned();
|
||||
img.width = st.readUnsigned();
|
||||
img.height = st.readUnsigned();
|
||||
|
||||
var bits = byteToBitArr(st.readByte());
|
||||
img.lctFlag = bits.shift();
|
||||
img.interlaced = bits.shift();
|
||||
img.sorted = bits.shift();
|
||||
img.reserved = bits.splice(0, 2);
|
||||
img.lctSize = bitsToNum(bits.splice(0, 3));
|
||||
|
||||
if (img.lctFlag) {
|
||||
img.lct = parseCT(1 << (img.lctSize + 1));
|
||||
}
|
||||
|
||||
img.lzwMinCodeSize = st.readByte();
|
||||
|
||||
var lzwData = readSubBlocks();
|
||||
|
||||
img.pixels = lzwDecode(img.lzwMinCodeSize, lzwData);
|
||||
|
||||
if (img.interlaced) { // Move
|
||||
img.pixels = deinterlace(img.pixels, img.width);
|
||||
}
|
||||
|
||||
handler.img && handler.img(img);
|
||||
};
|
||||
|
||||
var parseBlock = function () {
|
||||
var block = {};
|
||||
block.sentinel = st.readByte();
|
||||
|
||||
switch (String.fromCharCode(block.sentinel)) { // For ease of matching
|
||||
case '!':
|
||||
block.type = 'ext';
|
||||
parseExt(block);
|
||||
break;
|
||||
case ',':
|
||||
block.type = 'img';
|
||||
parseImg(block);
|
||||
break;
|
||||
case ';':
|
||||
block.type = 'eof';
|
||||
handler.eof && handler.eof(block);
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unknown block: 0x' + block.sentinel.toString(16)); // TODO: Pad this with a 0.
|
||||
}
|
||||
|
||||
if (block.type !== 'eof') setTimeout(parseBlock, 0);
|
||||
};
|
||||
|
||||
var parse = function () {
|
||||
parseHeader();
|
||||
setTimeout(parseBlock, 0);
|
||||
};
|
||||
|
||||
parse();
|
||||
};
|
||||
|
||||
var SuperGif = function ( opts ) {
|
||||
var options = {
|
||||
//viewport position
|
||||
vp_l: 0,
|
||||
vp_t: 0,
|
||||
vp_w: null,
|
||||
vp_h: null,
|
||||
//canvas sizes
|
||||
c_w: null,
|
||||
c_h: null
|
||||
};
|
||||
for (var i in opts ) { options[i] = opts[i] }
|
||||
if (options.vp_w && options.vp_h) options.is_vp = true;
|
||||
|
||||
var stream;
|
||||
var hdr;
|
||||
|
||||
var loadError = null;
|
||||
var loading = false;
|
||||
|
||||
var transparency = null;
|
||||
var delay = null;
|
||||
var disposalMethod = null;
|
||||
var disposalRestoreFromIdx = null;
|
||||
var lastDisposalMethod = null;
|
||||
var frame = null;
|
||||
var lastImg = null;
|
||||
|
||||
var playing = true;
|
||||
var forward = true;
|
||||
|
||||
var ctx_scaled = false;
|
||||
|
||||
var frames = [];
|
||||
var frameOffsets = []; // elements have .x and .y properties
|
||||
|
||||
var gif = options.gif;
|
||||
if (typeof options.auto_play == 'undefined')
|
||||
options.auto_play = (!gif.getAttribute('rel:auto_play') || gif.getAttribute('rel:auto_play') == '1');
|
||||
|
||||
var onEndListener = (options.hasOwnProperty('on_end') ? options.on_end : null);
|
||||
var loopDelay = (options.hasOwnProperty('loop_delay') ? options.loop_delay : 0);
|
||||
var overrideLoopMode = (options.hasOwnProperty('loop_mode') ? options.loop_mode : 'auto');
|
||||
var drawWhileLoading = (options.hasOwnProperty('draw_while_loading') ? options.draw_while_loading : true);
|
||||
var showProgressBar = drawWhileLoading ? (options.hasOwnProperty('show_progress_bar') ? options.show_progress_bar : true) : false;
|
||||
var progressBarHeight = (options.hasOwnProperty('progressbar_height') ? options.progressbar_height : 25);
|
||||
var progressBarBackgroundColor = (options.hasOwnProperty('progressbar_background_color') ? options.progressbar_background_color : 'rgba(255,255,255,0.4)');
|
||||
var progressBarForegroundColor = (options.hasOwnProperty('progressbar_foreground_color') ? options.progressbar_foreground_color : 'rgba(255,0,22,.8)');
|
||||
|
||||
var clear = function () {
|
||||
transparency = null;
|
||||
delay = null;
|
||||
lastDisposalMethod = disposalMethod;
|
||||
disposalMethod = null;
|
||||
frame = null;
|
||||
};
|
||||
|
||||
// XXX: There's probably a better way to handle catching exceptions when
|
||||
// callbacks are involved.
|
||||
var doParse = function () {
|
||||
try {
|
||||
parseGIF(stream, handler);
|
||||
}
|
||||
catch (err) {
|
||||
doLoadError('parse');
|
||||
}
|
||||
};
|
||||
|
||||
var doText = function (text) {
|
||||
toolbar.innerHTML = text; // innerText? Escaping? Whatever.
|
||||
toolbar.style.visibility = 'visible';
|
||||
};
|
||||
|
||||
var setSizes = function(w, h) {
|
||||
canvas.width = w * get_canvas_scale();
|
||||
canvas.height = h * get_canvas_scale();
|
||||
toolbar.style.minWidth = ( w * get_canvas_scale() ) + 'px';
|
||||
|
||||
tmpCanvas.width = w;
|
||||
tmpCanvas.height = h;
|
||||
tmpCanvas.style.width = w + 'px';
|
||||
tmpCanvas.style.height = h + 'px';
|
||||
tmpCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);
|
||||
};
|
||||
|
||||
var setFrameOffset = function(frame, offset) {
|
||||
if (!frameOffsets[frame]) {
|
||||
frameOffsets[frame] = offset;
|
||||
return;
|
||||
}
|
||||
if (typeof offset.x !== 'undefined') {
|
||||
frameOffsets[frame].x = offset.x;
|
||||
}
|
||||
if (typeof offset.y !== 'undefined') {
|
||||
frameOffsets[frame].y = offset.y;
|
||||
}
|
||||
};
|
||||
|
||||
var doShowProgress = function (pos, length, draw) {
|
||||
if (draw && showProgressBar) {
|
||||
var height = progressBarHeight;
|
||||
var left, mid, top, width;
|
||||
if (options.is_vp) {
|
||||
if (!ctx_scaled) {
|
||||
top = (options.vp_t + options.vp_h - height);
|
||||
height = height;
|
||||
left = options.vp_l;
|
||||
mid = left + (pos / length) * options.vp_w;
|
||||
width = canvas.width;
|
||||
} else {
|
||||
top = (options.vp_t + options.vp_h - height) / get_canvas_scale();
|
||||
height = height / get_canvas_scale();
|
||||
left = (options.vp_l / get_canvas_scale() );
|
||||
mid = left + (pos / length) * (options.vp_w / get_canvas_scale());
|
||||
width = canvas.width / get_canvas_scale();
|
||||
}
|
||||
//some debugging, draw rect around viewport
|
||||
if (false) {
|
||||
if (!ctx_scaled) {
|
||||
var l = options.vp_l, t = options.vp_t;
|
||||
var w = options.vp_w, h = options.vp_h;
|
||||
} else {
|
||||
var l = options.vp_l/get_canvas_scale(), t = options.vp_t/get_canvas_scale();
|
||||
var w = options.vp_w/get_canvas_scale(), h = options.vp_h/get_canvas_scale();
|
||||
}
|
||||
ctx.rect(l,t,w,h);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
else {
|
||||
top = (canvas.height - height) / (ctx_scaled ? get_canvas_scale() : 1);
|
||||
mid = ((pos / length) * canvas.width) / (ctx_scaled ? get_canvas_scale() : 1);
|
||||
width = canvas.width / (ctx_scaled ? get_canvas_scale() : 1 );
|
||||
height /= ctx_scaled ? get_canvas_scale() : 1;
|
||||
}
|
||||
|
||||
ctx.fillStyle = progressBarBackgroundColor;
|
||||
ctx.fillRect(mid, top, width - mid, height);
|
||||
|
||||
ctx.fillStyle = progressBarForegroundColor;
|
||||
ctx.fillRect(0, top, mid, height);
|
||||
}
|
||||
};
|
||||
|
||||
var doLoadError = function (originOfError) {
|
||||
var drawError = function () {
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.fillRect(0, 0, options.c_w ? options.c_w : hdr.width, options.c_h ? options.c_h : hdr.height);
|
||||
ctx.strokeStyle = 'red';
|
||||
ctx.lineWidth = 3;
|
||||
ctx.moveTo(0, 0);
|
||||
ctx.lineTo(options.c_w ? options.c_w : hdr.width, options.c_h ? options.c_h : hdr.height);
|
||||
ctx.moveTo(0, options.c_h ? options.c_h : hdr.height);
|
||||
ctx.lineTo(options.c_w ? options.c_w : hdr.width, 0);
|
||||
ctx.stroke();
|
||||
};
|
||||
|
||||
loadError = originOfError;
|
||||
hdr = {
|
||||
width: gif.width,
|
||||
height: gif.height
|
||||
}; // Fake header.
|
||||
frames = [];
|
||||
drawError();
|
||||
};
|
||||
|
||||
var doHdr = function (_hdr) {
|
||||
hdr = _hdr;
|
||||
setSizes(hdr.width, hdr.height)
|
||||
};
|
||||
|
||||
var doGCE = function (gce) {
|
||||
pushFrame();
|
||||
clear();
|
||||
transparency = gce.transparencyGiven ? gce.transparencyIndex : null;
|
||||
delay = gce.delayTime;
|
||||
disposalMethod = gce.disposalMethod;
|
||||
// We don't have much to do with the rest of GCE.
|
||||
};
|
||||
|
||||
var pushFrame = function () {
|
||||
if (!frame) return;
|
||||
frames.push({
|
||||
data: frame.getImageData(0, 0, hdr.width, hdr.height),
|
||||
delay: delay
|
||||
});
|
||||
frameOffsets.push({ x: 0, y: 0 });
|
||||
};
|
||||
|
||||
var doImg = function (img) {
|
||||
if (!frame) frame = tmpCanvas.getContext('2d');
|
||||
|
||||
var currIdx = frames.length;
|
||||
|
||||
//ct = color table, gct = global color table
|
||||
var ct = img.lctFlag ? img.lct : hdr.gct; // TODO: What if neither exists?
|
||||
|
||||
/*
|
||||
Disposal method indicates the way in which the graphic is to
|
||||
be treated after being displayed.
|
||||
|
||||
Values : 0 - No disposal specified. The decoder is
|
||||
not required to take any action.
|
||||
1 - Do not dispose. The graphic is to be left
|
||||
in place.
|
||||
2 - Restore to background color. The area used by the
|
||||
graphic must be restored to the background color.
|
||||
3 - Restore to previous. The decoder is required to
|
||||
restore the area overwritten by the graphic with
|
||||
what was there prior to rendering the graphic.
|
||||
|
||||
Importantly, "previous" means the frame state
|
||||
after the last disposal of method 0, 1, or 2.
|
||||
*/
|
||||
if (currIdx > 0) {
|
||||
if (lastDisposalMethod === 3) {
|
||||
// Restore to previous
|
||||
// If we disposed every frame including first frame up to this point, then we have
|
||||
// no composited frame to restore to. In this case, restore to background instead.
|
||||
if (disposalRestoreFromIdx !== null) {
|
||||
frame.putImageData(frames[disposalRestoreFromIdx].data, 0, 0);
|
||||
} else {
|
||||
frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height);
|
||||
}
|
||||
} else {
|
||||
disposalRestoreFromIdx = currIdx - 1;
|
||||
}
|
||||
|
||||
if (lastDisposalMethod === 2) {
|
||||
// Restore to background color
|
||||
// Browser implementations historically restore to transparent; we do the same.
|
||||
// http://www.wizards-toolkit.org/discourse-server/viewtopic.php?f=1&t=21172#p86079
|
||||
frame.clearRect(lastImg.leftPos, lastImg.topPos, lastImg.width, lastImg.height);
|
||||
}
|
||||
}
|
||||
// else, Undefined/Do not dispose.
|
||||
// frame contains final pixel data from the last frame; do nothing
|
||||
|
||||
//Get existing pixels for img region after applying disposal method
|
||||
var imgData = frame.getImageData(img.leftPos, img.topPos, img.width, img.height);
|
||||
|
||||
//apply color table colors
|
||||
img.pixels.forEach(function (pixel, i) {
|
||||
// imgData.data === [R,G,B,A,R,G,B,A,...]
|
||||
if (pixel !== transparency) {
|
||||
imgData.data[i * 4 + 0] = ct[pixel][0];
|
||||
imgData.data[i * 4 + 1] = ct[pixel][1];
|
||||
imgData.data[i * 4 + 2] = ct[pixel][2];
|
||||
imgData.data[i * 4 + 3] = 255; // Opaque.
|
||||
}
|
||||
});
|
||||
|
||||
frame.putImageData(imgData, img.leftPos, img.topPos);
|
||||
|
||||
if (!ctx_scaled) {
|
||||
ctx.scale(get_canvas_scale(),get_canvas_scale());
|
||||
ctx_scaled = true;
|
||||
}
|
||||
|
||||
// We could use the on-page canvas directly, except that we draw a progress
|
||||
// bar for each image chunk (not just the final image).
|
||||
if (drawWhileLoading) {
|
||||
ctx.drawImage(tmpCanvas, 0, 0);
|
||||
drawWhileLoading = options.auto_play;
|
||||
}
|
||||
|
||||
lastImg = img;
|
||||
};
|
||||
|
||||
var player = (function () {
|
||||
var i = -1;
|
||||
var iterationCount = 0;
|
||||
|
||||
var showingInfo = false;
|
||||
var pinned = false;
|
||||
|
||||
/**
|
||||
* Gets the index of the frame "up next".
|
||||
* @returns {number}
|
||||
*/
|
||||
var getNextFrameNo = function () {
|
||||
var delta = (forward ? 1 : -1);
|
||||
return (i + delta + frames.length) % frames.length;
|
||||
};
|
||||
|
||||
var stepFrame = function (amount) { // XXX: Name is confusing.
|
||||
i = i + amount;
|
||||
|
||||
putFrame();
|
||||
};
|
||||
|
||||
var step = (function () {
|
||||
var stepping = false;
|
||||
|
||||
var completeLoop = function () {
|
||||
if (onEndListener !== null)
|
||||
onEndListener(gif);
|
||||
iterationCount++;
|
||||
|
||||
if (overrideLoopMode !== false || iterationCount < 0) {
|
||||
doStep();
|
||||
} else {
|
||||
stepping = false;
|
||||
playing = false;
|
||||
}
|
||||
};
|
||||
|
||||
var doStep = function () {
|
||||
stepping = playing;
|
||||
if (!stepping) return;
|
||||
|
||||
stepFrame(1);
|
||||
var delay = frames[i].delay * 10;
|
||||
if (!delay) delay = 100; // FIXME: Should this even default at all? What should it be?
|
||||
|
||||
var nextFrameNo = getNextFrameNo();
|
||||
if (nextFrameNo === 0) {
|
||||
delay += loopDelay;
|
||||
setTimeout(completeLoop, delay);
|
||||
} else {
|
||||
setTimeout(doStep, delay);
|
||||
}
|
||||
};
|
||||
|
||||
return function () {
|
||||
if (!stepping) setTimeout(doStep, 0);
|
||||
};
|
||||
}());
|
||||
|
||||
var putFrame = function () {
|
||||
var offset;
|
||||
i = parseInt(i, 10);
|
||||
|
||||
if (i > frames.length - 1){
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (i < 0){
|
||||
i = 0;
|
||||
}
|
||||
|
||||
offset = frameOffsets[i];
|
||||
|
||||
tmpCanvas.getContext("2d").putImageData(frames[i].data, offset.x, offset.y);
|
||||
ctx.globalCompositeOperation = "copy";
|
||||
ctx.drawImage(tmpCanvas, 0, 0);
|
||||
};
|
||||
|
||||
var play = function () {
|
||||
playing = true;
|
||||
step();
|
||||
};
|
||||
|
||||
var pause = function () {
|
||||
playing = false;
|
||||
};
|
||||
|
||||
|
||||
return {
|
||||
init: function () {
|
||||
if (loadError) return;
|
||||
|
||||
if ( ! (options.c_w && options.c_h) ) {
|
||||
ctx.scale(get_canvas_scale(),get_canvas_scale());
|
||||
}
|
||||
|
||||
if (options.auto_play) {
|
||||
step();
|
||||
}
|
||||
else {
|
||||
i = 0;
|
||||
putFrame();
|
||||
}
|
||||
},
|
||||
step: step,
|
||||
play: play,
|
||||
pause: pause,
|
||||
playing: playing,
|
||||
move_relative: stepFrame,
|
||||
current_frame: function() { return i; },
|
||||
length: function() { return frames.length },
|
||||
move_to: function ( frame_idx ) {
|
||||
i = frame_idx;
|
||||
putFrame();
|
||||
}
|
||||
}
|
||||
}());
|
||||
|
||||
var doDecodeProgress = function (draw) {
|
||||
doShowProgress(stream.pos, stream.data.length, draw);
|
||||
};
|
||||
|
||||
var doNothing = function () {};
|
||||
/**
|
||||
* @param{boolean=} draw Whether to draw progress bar or not; this is not idempotent because of translucency.
|
||||
* Note that this means that the text will be unsynchronized with the progress bar on non-frames;
|
||||
* but those are typically so small (GCE etc.) that it doesn't really matter. TODO: Do this properly.
|
||||
*/
|
||||
var withProgress = function (fn, draw) {
|
||||
return function (block) {
|
||||
fn(block);
|
||||
doDecodeProgress(draw);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
var handler = {
|
||||
hdr: withProgress(doHdr),
|
||||
gce: withProgress(doGCE),
|
||||
com: withProgress(doNothing),
|
||||
// I guess that's all for now.
|
||||
app: {
|
||||
// TODO: Is there much point in actually supporting iterations?
|
||||
NETSCAPE: withProgress(doNothing)
|
||||
},
|
||||
img: withProgress(doImg, true),
|
||||
eof: function (block) {
|
||||
//toolbar.style.display = '';
|
||||
pushFrame();
|
||||
doDecodeProgress(false);
|
||||
if ( ! (options.c_w && options.c_h) ) {
|
||||
canvas.width = hdr.width * get_canvas_scale();
|
||||
canvas.height = hdr.height * get_canvas_scale();
|
||||
}
|
||||
player.init();
|
||||
loading = false;
|
||||
if (load_callback) {
|
||||
load_callback(gif);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var init = function () {
|
||||
var parent = gif.parentNode;
|
||||
|
||||
var div = document.createElement('div');
|
||||
canvas = document.createElement('canvas');
|
||||
ctx = canvas.getContext('2d');
|
||||
toolbar = document.createElement('div');
|
||||
|
||||
tmpCanvas = document.createElement('canvas');
|
||||
|
||||
div.width = canvas.width = gif.width;
|
||||
div.height = canvas.height = gif.height;
|
||||
toolbar.style.minWidth = gif.width + 'px';
|
||||
|
||||
div.className = 'jsgif';
|
||||
toolbar.className = 'jsgif_toolbar';
|
||||
div.appendChild(canvas);
|
||||
div.appendChild(toolbar);
|
||||
|
||||
parent.insertBefore(div, gif);
|
||||
parent.removeChild(gif);
|
||||
|
||||
if (options.c_w && options.c_h) setSizes(options.c_w, options.c_h);
|
||||
initialized=true;
|
||||
};
|
||||
|
||||
var get_canvas_scale = function() {
|
||||
var scale;
|
||||
if (options.max_width && hdr && hdr.width > options.max_width) {
|
||||
scale = options.max_width / hdr.width;
|
||||
}
|
||||
else {
|
||||
scale = 1;
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
var canvas, ctx, toolbar, tmpCanvas;
|
||||
var initialized = false;
|
||||
var load_callback = false;
|
||||
|
||||
var load_setup = function(callback) {
|
||||
if (loading) return false;
|
||||
if (callback) load_callback = callback;
|
||||
else load_callback = false;
|
||||
|
||||
loading = true;
|
||||
frames = [];
|
||||
clear();
|
||||
disposalRestoreFromIdx = null;
|
||||
lastDisposalMethod = null;
|
||||
frame = null;
|
||||
lastImg = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return {
|
||||
// play controls
|
||||
play: player.play,
|
||||
pause: player.pause,
|
||||
move_relative: player.move_relative,
|
||||
move_to: player.move_to,
|
||||
|
||||
// getters for instance vars
|
||||
get_playing : function() { return playing },
|
||||
get_canvas : function() { return canvas },
|
||||
get_canvas_scale : function() { return get_canvas_scale() },
|
||||
get_loading : function() { return loading },
|
||||
get_auto_play : function() { return options.auto_play },
|
||||
get_length : function() { return player.length() },
|
||||
get_current_frame: function() { return player.current_frame() },
|
||||
load_url: function(src,callback){
|
||||
if (!load_setup(callback)) return;
|
||||
|
||||
var h = new XMLHttpRequest();
|
||||
// new browsers (XMLHttpRequest2-compliant)
|
||||
h.open('GET', src, true);
|
||||
|
||||
if ('overrideMimeType' in h) {
|
||||
h.overrideMimeType('text/plain; charset=x-user-defined');
|
||||
}
|
||||
|
||||
// old browsers (XMLHttpRequest-compliant)
|
||||
else if ('responseType' in h) {
|
||||
h.responseType = 'arraybuffer';
|
||||
}
|
||||
|
||||
// IE9 (Microsoft.XMLHTTP-compliant)
|
||||
else {
|
||||
h.setRequestHeader('Accept-Charset', 'x-user-defined');
|
||||
}
|
||||
|
||||
h.onloadstart = function() {
|
||||
// Wait until connection is opened to replace the gif element with a canvas to avoid a blank img
|
||||
if (!initialized) init();
|
||||
};
|
||||
h.onload = function(e) {
|
||||
if (this.status != 200) {
|
||||
doLoadError('xhr - response');
|
||||
}
|
||||
// emulating response field for IE9
|
||||
if (!('response' in this)) {
|
||||
this.response = new VBArray(this.responseText).toArray().map(String.fromCharCode).join('');
|
||||
}
|
||||
var data = this.response;
|
||||
if (data.toString().indexOf("ArrayBuffer") > 0) {
|
||||
data = new Uint8Array(data);
|
||||
}
|
||||
|
||||
stream = new Stream(data);
|
||||
setTimeout(doParse, 0);
|
||||
};
|
||||
h.onprogress = function (e) {
|
||||
if (e.lengthComputable) doShowProgress(e.loaded, e.total, true);
|
||||
};
|
||||
h.onerror = function() { doLoadError('xhr'); };
|
||||
h.send();
|
||||
},
|
||||
load: function (callback) {
|
||||
this.load_url(gif.getAttribute('rel:animated_src') || gif.src,callback);
|
||||
},
|
||||
load_raw: function(arr, callback) {
|
||||
if (!load_setup(callback)) return;
|
||||
if (!initialized) init();
|
||||
stream = new Stream(arr);
|
||||
setTimeout(doParse, 0);
|
||||
},
|
||||
set_frame_offset: setFrameOffset
|
||||
};
|
||||
};
|
||||
|
||||
return SuperGif;
|
||||
}));
|
||||
|
||||
|
887
example/js/pbf.js
Normal file
887
example/js/pbf.js
Normal file
@ -0,0 +1,887 @@
|
||||
/**
|
||||
* Minified by jsDelivr using Terser v5.19.2.
|
||||
* Original file: /npm/pbf@4.0.1/index.js
|
||||
*
|
||||
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
||||
*/
|
||||
const SHIFT_LEFT_32 = 4294967296, SHIFT_RIGHT_32 = 1 / 4294967296, TEXT_DECODER_MIN_LENGTH = 12,
|
||||
utf8TextDecoder = "undefined" == typeof TextDecoder ? null : new TextDecoder("utf-8"), PBF_VARINT = 0,
|
||||
PBF_FIXED64 = 1, PBF_BYTES = 2, PBF_FIXED32 = 5;
|
||||
|
||||
class Pbf {
|
||||
constructor(t = new Uint8Array(16)) {
|
||||
this.buf = ArrayBuffer.isView(t) ? t : new Uint8Array(t), this.dataView = new DataView(this.buf.buffer), this.pos = 0, this.type = 0, this.length = this.buf.length
|
||||
}
|
||||
|
||||
readFields(t, e, i = this.length) {
|
||||
for (; this.pos < i;) {
|
||||
const i = this.readVarint(), s = i >> 3, r = this.pos;
|
||||
this.type = 7 & i, t(s, e, this), this.pos === r && this.skip(i)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
readMessage(t, e) {
|
||||
return this.readFields(t, e, this.readVarint() + this.pos)
|
||||
}
|
||||
|
||||
readFixed32() {
|
||||
const t = this.dataView.getUint32(this.pos, !0);
|
||||
return this.pos += 4, t
|
||||
}
|
||||
|
||||
readSFixed32() {
|
||||
const t = this.dataView.getInt32(this.pos, !0);
|
||||
return this.pos += 4, t
|
||||
}
|
||||
|
||||
readFixed64() {
|
||||
const t = this.dataView.getUint32(this.pos, !0) + 4294967296 * this.dataView.getUint32(this.pos + 4, !0);
|
||||
return this.pos += 8, t
|
||||
}
|
||||
|
||||
readSFixed64() {
|
||||
const t = this.dataView.getUint32(this.pos, !0) + 4294967296 * this.dataView.getInt32(this.pos + 4, !0);
|
||||
return this.pos += 8, t
|
||||
}
|
||||
|
||||
readFloat() {
|
||||
const t = this.dataView.getFloat32(this.pos, !0);
|
||||
return this.pos += 4, t
|
||||
}
|
||||
|
||||
readDouble() {
|
||||
const t = this.dataView.getFloat64(this.pos, !0);
|
||||
return this.pos += 8, t
|
||||
}
|
||||
|
||||
readVarint(t) {
|
||||
const e = this.buf;
|
||||
let i, s;
|
||||
return s = e[this.pos++], i = 127 & s, s < 128 ? i : (s = e[this.pos++], i |= (127 & s) << 7, s < 128 ? i : (s = e[this.pos++], i |= (127 & s) << 14, s < 128 ? i : (s = e[this.pos++], i |= (127 & s) << 21, s < 128 ? i : (s = e[this.pos], i |= (15 & s) << 28, readVarintRemainder(i, t, this)))))
|
||||
}
|
||||
|
||||
readVarint64() {
|
||||
return this.readVarint(!0)
|
||||
}
|
||||
|
||||
readSVarint() {
|
||||
const t = this.readVarint();
|
||||
return t % 2 == 1 ? (t + 1) / -2 : t / 2
|
||||
}
|
||||
|
||||
readBoolean() {
|
||||
return Boolean(this.readVarint())
|
||||
}
|
||||
|
||||
readString() {
|
||||
const t = this.readVarint() + this.pos, e = this.pos;
|
||||
return this.pos = t, t - e >= 12 && utf8TextDecoder ? utf8TextDecoder.decode(this.buf.subarray(e, t)) : readUtf8(this.buf, e, t)
|
||||
}
|
||||
|
||||
readBytes() {
|
||||
const t = this.readVarint() + this.pos, e = this.buf.subarray(this.pos, t);
|
||||
return this.pos = t, e
|
||||
}
|
||||
|
||||
readPackedVarint(t = [], e) {
|
||||
const i = this.readPackedEnd();
|
||||
for (; this.pos < i;) t.push(this.readVarint(e));
|
||||
return t
|
||||
}
|
||||
|
||||
readPackedSVarint(t = []) {
|
||||
const e = this.readPackedEnd();
|
||||
for (; this.pos < e;) t.push(this.readSVarint());
|
||||
return t
|
||||
}
|
||||
|
||||
readPackedBoolean(t = []) {
|
||||
const e = this.readPackedEnd();
|
||||
for (; this.pos < e;) t.push(this.readBoolean());
|
||||
return t
|
||||
}
|
||||
|
||||
readPackedFloat(t = []) {
|
||||
const e = this.readPackedEnd();
|
||||
for (; this.pos < e;) t.push(this.readFloat());
|
||||
return t
|
||||
}
|
||||
|
||||
readPackedDouble(t = []) {
|
||||
const e = this.readPackedEnd();
|
||||
for (; this.pos < e;) t.push(this.readDouble());
|
||||
return t
|
||||
}
|
||||
|
||||
readPackedFixed32(t = []) {
|
||||
const e = this.readPackedEnd();
|
||||
for (; this.pos < e;) t.push(this.readFixed32());
|
||||
return t
|
||||
}
|
||||
|
||||
readPackedSFixed32(t = []) {
|
||||
const e = this.readPackedEnd();
|
||||
for (; this.pos < e;) t.push(this.readSFixed32());
|
||||
return t
|
||||
}
|
||||
|
||||
readPackedFixed64(t = []) {
|
||||
const e = this.readPackedEnd();
|
||||
for (; this.pos < e;) t.push(this.readFixed64());
|
||||
return t
|
||||
}
|
||||
|
||||
readPackedSFixed64(t = []) {
|
||||
const e = this.readPackedEnd();
|
||||
for (; this.pos < e;) t.push(this.readSFixed64());
|
||||
return t
|
||||
}
|
||||
|
||||
readPackedEnd() {
|
||||
return 2 === this.type ? this.readVarint() + this.pos : this.pos + 1
|
||||
}
|
||||
|
||||
skip(t) {
|
||||
const e = 7 & t;
|
||||
if (0 === e) for (; this.buf[this.pos++] > 127;) ; else if (2 === e) this.pos = this.readVarint() + this.pos; else if (5 === e) this.pos += 4; else {
|
||||
if (1 !== e) throw new Error(`Unimplemented type: ${e}`);
|
||||
this.pos += 8
|
||||
}
|
||||
}
|
||||
|
||||
writeTag(t, e) {
|
||||
this.writeVarint(t << 3 | e)
|
||||
}
|
||||
|
||||
realloc(t) {
|
||||
let e = this.length || 16;
|
||||
for (; e < this.pos + t;) e *= 2;
|
||||
if (e !== this.length) {
|
||||
const t = new Uint8Array(e);
|
||||
t.set(this.buf), this.buf = t, this.dataView = new DataView(t.buffer), this.length = e
|
||||
}
|
||||
}
|
||||
|
||||
finish() {
|
||||
return this.length = this.pos, this.pos = 0, this.buf.subarray(0, this.length)
|
||||
}
|
||||
|
||||
writeFixed32(t) {
|
||||
this.realloc(4), this.dataView.setInt32(this.pos, t, !0), this.pos += 4
|
||||
}
|
||||
|
||||
writeSFixed32(t) {
|
||||
this.realloc(4), this.dataView.setInt32(this.pos, t, !0), this.pos += 4
|
||||
}
|
||||
|
||||
writeFixed64(t) {
|
||||
this.realloc(8), this.dataView.setInt32(this.pos, -1 & t, !0), this.dataView.setInt32(this.pos + 4, Math.floor(t * SHIFT_RIGHT_32), !0), this.pos += 8
|
||||
}
|
||||
|
||||
writeSFixed64(t) {
|
||||
this.realloc(8), this.dataView.setInt32(this.pos, -1 & t, !0), this.dataView.setInt32(this.pos + 4, Math.floor(t * SHIFT_RIGHT_32), !0), this.pos += 8
|
||||
}
|
||||
|
||||
writeVarint(t) {
|
||||
(t = +t || 0) > 268435455 || t < 0 ? writeBigVarint(t, this) : (this.realloc(4), this.buf[this.pos++] = 127 & t | (t > 127 ? 128 : 0), t <= 127 || (this.buf[this.pos++] = 127 & (t >>>= 7) | (t > 127 ? 128 : 0), t <= 127 || (this.buf[this.pos++] = 127 & (t >>>= 7) | (t > 127 ? 128 : 0), t <= 127 || (this.buf[this.pos++] = t >>> 7 & 127))))
|
||||
}
|
||||
|
||||
writeSVarint(t) {
|
||||
this.writeVarint(t < 0 ? 2 * -t - 1 : 2 * t)
|
||||
}
|
||||
|
||||
writeBoolean(t) {
|
||||
this.writeVarint(+t)
|
||||
}
|
||||
|
||||
writeString(t) {
|
||||
t = String(t), this.realloc(4 * t.length), this.pos++;
|
||||
const e = this.pos;
|
||||
this.pos = writeUtf8(this.buf, t, this.pos);
|
||||
const i = this.pos - e;
|
||||
i >= 128 && makeRoomForExtraLength(e, i, this), this.pos = e - 1, this.writeVarint(i), this.pos += i
|
||||
}
|
||||
|
||||
writeFloat(t) {
|
||||
this.realloc(4), this.dataView.setFloat32(this.pos, t, !0), this.pos += 4
|
||||
}
|
||||
|
||||
writeDouble(t) {
|
||||
this.realloc(8), this.dataView.setFloat64(this.pos, t, !0), this.pos += 8
|
||||
}
|
||||
|
||||
writeBytes(t) {
|
||||
const e = t.length;
|
||||
this.writeVarint(e), this.realloc(e);
|
||||
for (let i = 0; i < e; i++) this.buf[this.pos++] = t[i]
|
||||
}
|
||||
|
||||
writeRawMessage(t, e) {
|
||||
this.pos++;
|
||||
const i = this.pos;
|
||||
t(e, this);
|
||||
const s = this.pos - i;
|
||||
s >= 128 && makeRoomForExtraLength(i, s, this), this.pos = i - 1, this.writeVarint(s), this.pos += s
|
||||
}
|
||||
|
||||
writeMessage(t, e, i) {
|
||||
this.writeTag(t, 2), this.writeRawMessage(e, i)
|
||||
}
|
||||
|
||||
writePackedVarint(t, e) {
|
||||
e.length && this.writeMessage(t, writePackedVarint, e)
|
||||
}
|
||||
|
||||
writePackedSVarint(t, e) {
|
||||
e.length && this.writeMessage(t, writePackedSVarint, e)
|
||||
}
|
||||
|
||||
writePackedBoolean(t, e) {
|
||||
e.length && this.writeMessage(t, writePackedBoolean, e)
|
||||
}
|
||||
|
||||
writePackedFloat(t, e) {
|
||||
e.length && this.writeMessage(t, writePackedFloat, e)
|
||||
}
|
||||
|
||||
writePackedDouble(t, e) {
|
||||
e.length && this.writeMessage(t, writePackedDouble, e)
|
||||
}
|
||||
|
||||
writePackedFixed32(t, e) {
|
||||
e.length && this.writeMessage(t, writePackedFixed32, e)
|
||||
}
|
||||
|
||||
writePackedSFixed32(t, e) {
|
||||
e.length && this.writeMessage(t, writePackedSFixed32, e)
|
||||
}
|
||||
|
||||
writePackedFixed64(t, e) {
|
||||
e.length && this.writeMessage(t, writePackedFixed64, e)
|
||||
}
|
||||
|
||||
writePackedSFixed64(t, e) {
|
||||
e.length && this.writeMessage(t, writePackedSFixed64, e)
|
||||
}
|
||||
|
||||
writeBytesField(t, e) {
|
||||
this.writeTag(t, 2), this.writeBytes(e)
|
||||
}
|
||||
|
||||
writeFixed32Field(t, e) {
|
||||
this.writeTag(t, 5), this.writeFixed32(e)
|
||||
}
|
||||
|
||||
writeSFixed32Field(t, e) {
|
||||
this.writeTag(t, 5), this.writeSFixed32(e)
|
||||
}
|
||||
|
||||
writeFixed64Field(t, e) {
|
||||
this.writeTag(t, 1), this.writeFixed64(e)
|
||||
}
|
||||
|
||||
writeSFixed64Field(t, e) {
|
||||
this.writeTag(t, 1), this.writeSFixed64(e)
|
||||
}
|
||||
|
||||
writeVarintField(t, e) {
|
||||
this.writeTag(t, 0), this.writeVarint(e)
|
||||
}
|
||||
|
||||
writeSVarintField(t, e) {
|
||||
this.writeTag(t, 0), this.writeSVarint(e)
|
||||
}
|
||||
|
||||
writeStringField(t, e) {
|
||||
this.writeTag(t, 2), this.writeString(e)
|
||||
}
|
||||
|
||||
writeFloatField(t, e) {
|
||||
this.writeTag(t, 5), this.writeFloat(e)
|
||||
}
|
||||
|
||||
writeDoubleField(t, e) {
|
||||
this.writeTag(t, 1), this.writeDouble(e)
|
||||
}
|
||||
|
||||
writeBooleanField(t, e) {
|
||||
this.writeVarintField(t, +e)
|
||||
}
|
||||
}
|
||||
|
||||
// exports.Pbf = Pbf
|
||||
|
||||
function readVarintRemainder(t, e, i) {
|
||||
const s = i.buf;
|
||||
let r, a;
|
||||
if (a = s[i.pos++], r = (112 & a) >> 4, a < 128) return toNum(t, r, e);
|
||||
if (a = s[i.pos++], r |= (127 & a) << 3, a < 128) return toNum(t, r, e);
|
||||
if (a = s[i.pos++], r |= (127 & a) << 10, a < 128) return toNum(t, r, e);
|
||||
if (a = s[i.pos++], r |= (127 & a) << 17, a < 128) return toNum(t, r, e);
|
||||
if (a = s[i.pos++], r |= (127 & a) << 24, a < 128) return toNum(t, r, e);
|
||||
if (a = s[i.pos++], r |= (1 & a) << 31, a < 128) return toNum(t, r, e);
|
||||
throw new Error("Expected varint not more than 10 bytes")
|
||||
}
|
||||
|
||||
function toNum(t, e, i) {
|
||||
return i ? 4294967296 * e + (t >>> 0) : 4294967296 * (e >>> 0) + (t >>> 0)
|
||||
}
|
||||
|
||||
function writeBigVarint(t, e) {
|
||||
let i, s;
|
||||
if (t >= 0 ? (i = t % 4294967296 | 0, s = t / 4294967296 | 0) : (i = ~(-t % 4294967296), s = ~(-t / 4294967296), 4294967295 ^ i ? i = i + 1 | 0 : (i = 0, s = s + 1 | 0)), t >= 0x10000000000000000 || t < -0x10000000000000000) throw new Error("Given varint doesn't fit into 10 bytes");
|
||||
e.realloc(10), writeBigVarintLow(i, s, e), writeBigVarintHigh(s, e)
|
||||
}
|
||||
|
||||
function writeBigVarintLow(t, e, i) {
|
||||
i.buf[i.pos++] = 127 & t | 128, t >>>= 7, i.buf[i.pos++] = 127 & t | 128, t >>>= 7, i.buf[i.pos++] = 127 & t | 128, t >>>= 7, i.buf[i.pos++] = 127 & t | 128, t >>>= 7, i.buf[i.pos] = 127 & t
|
||||
}
|
||||
|
||||
function writeBigVarintHigh(t, e) {
|
||||
const i = (7 & t) << 4;
|
||||
e.buf[e.pos++] |= i | ((t >>>= 3) ? 128 : 0), t && (e.buf[e.pos++] = 127 & t | ((t >>>= 7) ? 128 : 0), t && (e.buf[e.pos++] = 127 & t | ((t >>>= 7) ? 128 : 0), t && (e.buf[e.pos++] = 127 & t | ((t >>>= 7) ? 128 : 0), t && (e.buf[e.pos++] = 127 & t | ((t >>>= 7) ? 128 : 0), t && (e.buf[e.pos++] = 127 & t)))))
|
||||
}
|
||||
|
||||
function makeRoomForExtraLength(t, e, i) {
|
||||
const s = e <= 16383 ? 1 : e <= 2097151 ? 2 : e <= 268435455 ? 3 : Math.floor(Math.log(e) / (7 * Math.LN2));
|
||||
i.realloc(s);
|
||||
for (let e = i.pos - 1; e >= t; e--) i.buf[e + s] = i.buf[e]
|
||||
}
|
||||
|
||||
function writePackedVarint(t, e) {
|
||||
for (let i = 0; i < t.length; i++) e.writeVarint(t[i])
|
||||
}
|
||||
|
||||
function writePackedSVarint(t, e) {
|
||||
for (let i = 0; i < t.length; i++) e.writeSVarint(t[i])
|
||||
}
|
||||
|
||||
function writePackedFloat(t, e) {
|
||||
for (let i = 0; i < t.length; i++) e.writeFloat(t[i])
|
||||
}
|
||||
|
||||
function writePackedDouble(t, e) {
|
||||
for (let i = 0; i < t.length; i++) e.writeDouble(t[i])
|
||||
}
|
||||
|
||||
function writePackedBoolean(t, e) {
|
||||
for (let i = 0; i < t.length; i++) e.writeBoolean(t[i])
|
||||
}
|
||||
|
||||
function writePackedFixed32(t, e) {
|
||||
for (let i = 0; i < t.length; i++) e.writeFixed32(t[i])
|
||||
}
|
||||
|
||||
function writePackedSFixed32(t, e) {
|
||||
for (let i = 0; i < t.length; i++) e.writeSFixed32(t[i])
|
||||
}
|
||||
|
||||
function writePackedFixed64(t, e) {
|
||||
for (let i = 0; i < t.length; i++) e.writeFixed64(t[i])
|
||||
}
|
||||
|
||||
function writePackedSFixed64(t, e) {
|
||||
for (let i = 0; i < t.length; i++) e.writeSFixed64(t[i])
|
||||
}
|
||||
|
||||
function readUtf8(t, e, i) {
|
||||
let s = "", r = e;
|
||||
for (; r < i;) {
|
||||
const e = t[r];
|
||||
let a, o, h, n = null, d = e > 239 ? 4 : e > 223 ? 3 : e > 191 ? 2 : 1;
|
||||
if (r + d > i) break;
|
||||
1 === d ? e < 128 && (n = e) : 2 === d ? (a = t[r + 1], 128 == (192 & a) && (n = (31 & e) << 6 | 63 & a, n <= 127 && (n = null))) : 3 === d ? (a = t[r + 1], o = t[r + 2], 128 == (192 & a) && 128 == (192 & o) && (n = (15 & e) << 12 | (63 & a) << 6 | 63 & o, (n <= 2047 || n >= 55296 && n <= 57343) && (n = null))) : 4 === d && (a = t[r + 1], o = t[r + 2], h = t[r + 3], 128 == (192 & a) && 128 == (192 & o) && 128 == (192 & h) && (n = (15 & e) << 18 | (63 & a) << 12 | (63 & o) << 6 | 63 & h, (n <= 65535 || n >= 1114112) && (n = null))), null === n ? (n = 65533, d = 1) : n > 65535 && (n -= 65536, s += String.fromCharCode(n >>> 10 & 1023 | 55296), n = 56320 | 1023 & n), s += String.fromCharCode(n), r += d
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
function writeUtf8(t, e, i) {
|
||||
for (let s, r, a = 0; a < e.length; a++) {
|
||||
if (s = e.charCodeAt(a), s > 55295 && s < 57344) {
|
||||
if (!r) {
|
||||
s > 56319 || a + 1 === e.length ? (t[i++] = 239, t[i++] = 191, t[i++] = 189) : r = s;
|
||||
continue
|
||||
}
|
||||
if (s < 56320) {
|
||||
t[i++] = 239, t[i++] = 191, t[i++] = 189, r = s;
|
||||
continue
|
||||
}
|
||||
s = r - 55296 << 10 | s - 56320 | 65536, r = null
|
||||
} else r && (t[i++] = 239, t[i++] = 191, t[i++] = 189, r = null);
|
||||
s < 128 ? t[i++] = s : (s < 2048 ? t[i++] = s >> 6 | 192 : (s < 65536 ? t[i++] = s >> 12 | 224 : (t[i++] = s >> 18 | 240, t[i++] = s >> 12 & 63 | 128), t[i++] = s >> 6 & 63 | 128), t[i++] = 63 & s | 128)
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
function Point(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
Point.prototype = {
|
||||
clone: function () {
|
||||
return new Point(this.x, this.y);
|
||||
},
|
||||
|
||||
add: function (p) {
|
||||
return this.clone()._add(p);
|
||||
},
|
||||
sub: function (p) {
|
||||
return this.clone()._sub(p);
|
||||
},
|
||||
mult: function (k) {
|
||||
return this.clone()._mult(k);
|
||||
},
|
||||
div: function (k) {
|
||||
return this.clone()._div(k);
|
||||
},
|
||||
rotate: function (a) {
|
||||
return this.clone()._rotate(a);
|
||||
},
|
||||
matMult: function (m) {
|
||||
return this.clone()._matMult(m);
|
||||
},
|
||||
unit: function () {
|
||||
return this.clone()._unit();
|
||||
},
|
||||
perp: function () {
|
||||
return this.clone()._perp();
|
||||
},
|
||||
round: function () {
|
||||
return this.clone()._round();
|
||||
},
|
||||
|
||||
mag: function () {
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y);
|
||||
},
|
||||
|
||||
equals: function (p) {
|
||||
return this.x === p.x &&
|
||||
this.y === p.y;
|
||||
},
|
||||
|
||||
dist: function (p) {
|
||||
return Math.sqrt(this.distSqr(p));
|
||||
},
|
||||
|
||||
distSqr: function (p) {
|
||||
var dx = p.x - this.x,
|
||||
dy = p.y - this.y;
|
||||
return dx * dx + dy * dy;
|
||||
},
|
||||
|
||||
angle: function () {
|
||||
return Math.atan2(this.y, this.x);
|
||||
},
|
||||
|
||||
angleTo: function (b) {
|
||||
return Math.atan2(this.y - b.y, this.x - b.x);
|
||||
},
|
||||
|
||||
angleWith: function (b) {
|
||||
return this.angleWithSep(b.x, b.y);
|
||||
},
|
||||
|
||||
// Find the angle of the two vectors, solving the formula for the cross product a x b = |a||b|sin(θ) for θ.
|
||||
angleWithSep: function (x, y) {
|
||||
return Math.atan2(
|
||||
this.x * y - this.y * x,
|
||||
this.x * x + this.y * y);
|
||||
},
|
||||
|
||||
_matMult: function (m) {
|
||||
var x = m[0] * this.x + m[1] * this.y,
|
||||
y = m[2] * this.x + m[3] * this.y;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
return this;
|
||||
},
|
||||
|
||||
_add: function (p) {
|
||||
this.x += p.x;
|
||||
this.y += p.y;
|
||||
return this;
|
||||
},
|
||||
|
||||
_sub: function (p) {
|
||||
this.x -= p.x;
|
||||
this.y -= p.y;
|
||||
return this;
|
||||
},
|
||||
|
||||
_mult: function (k) {
|
||||
this.x *= k;
|
||||
this.y *= k;
|
||||
return this;
|
||||
},
|
||||
|
||||
_div: function (k) {
|
||||
this.x /= k;
|
||||
this.y /= k;
|
||||
return this;
|
||||
},
|
||||
|
||||
_unit: function () {
|
||||
this._div(this.mag());
|
||||
return this;
|
||||
},
|
||||
|
||||
_perp: function () {
|
||||
var y = this.y;
|
||||
this.y = this.x;
|
||||
this.x = -y;
|
||||
return this;
|
||||
},
|
||||
|
||||
_rotate: function (angle) {
|
||||
var cos = Math.cos(angle),
|
||||
sin = Math.sin(angle),
|
||||
x = cos * this.x - sin * this.y,
|
||||
y = sin * this.x + cos * this.y;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
return this;
|
||||
},
|
||||
|
||||
_round: function () {
|
||||
this.x = Math.round(this.x);
|
||||
this.y = Math.round(this.y);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// constructs Point from an array if necessary
|
||||
Point.convert = function (a) {
|
||||
if (a instanceof Point) {
|
||||
return a;
|
||||
}
|
||||
if (Array.isArray(a)) {
|
||||
return new Point(a[0], a[1]);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
//# sourceMappingURL=/sm/91dc2634fd08444face2220488dd1b2296e475fe4a0f0781089e74342af5c955.map
|
||||
class TileFeature {
|
||||
constructor(pbf, end, extent, keys, values) {
|
||||
// Public
|
||||
this.properties = {};
|
||||
this.extent = extent;
|
||||
this.type = 0;
|
||||
|
||||
// Private
|
||||
this._pbf = pbf;
|
||||
this._geometry = -1;
|
||||
this._keys = keys;
|
||||
this._values = values;
|
||||
pbf.readFields(readFeature, this, end);
|
||||
}
|
||||
|
||||
types() {
|
||||
return ['Unknown', 'Point', 'LineString', 'Polygon'];
|
||||
}
|
||||
|
||||
loadGeometry() {
|
||||
var pbf = this._pbf;
|
||||
pbf.pos = this._geometry;
|
||||
|
||||
var end = pbf.readVarint() + pbf.pos,
|
||||
cmd = 1,
|
||||
length = 0,
|
||||
x = 0,
|
||||
y = 0,
|
||||
lines = [],
|
||||
line;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
if (!length) {
|
||||
var cmdLen = pbf.readVarint();
|
||||
cmd = cmdLen & 0x7;
|
||||
length = cmdLen >> 3;
|
||||
}
|
||||
|
||||
length--;
|
||||
if (cmd === 1 || cmd === 2) {
|
||||
x += pbf.readSVarint();
|
||||
y += pbf.readSVarint();
|
||||
|
||||
if (cmd === 1) { // moveTo
|
||||
if (line) lines.push(line);
|
||||
line = [];
|
||||
}
|
||||
|
||||
line.push(new Point(x, y));
|
||||
|
||||
} else if (cmd === 7) {
|
||||
|
||||
if (line) {
|
||||
line.push(line[0].clone()); // closePolygon
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new Error('unknown command ' + cmd);
|
||||
}
|
||||
}
|
||||
if (line) lines.push(line);
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
bbox() {
|
||||
var pbf = this._pbf;
|
||||
pbf.pos = this._geometry;
|
||||
|
||||
var end = pbf.readVarint() + pbf.pos,
|
||||
cmd = 1,
|
||||
length = 0,
|
||||
x = 0,
|
||||
y = 0,
|
||||
x1 = Infinity,
|
||||
x2 = -Infinity,
|
||||
y1 = Infinity,
|
||||
y2 = -Infinity;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
if (!length) {
|
||||
var cmdLen = pbf.readVarint();
|
||||
cmd = cmdLen & 0x7;
|
||||
length = cmdLen >> 3;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
if (cmd === 1 || cmd === 2) {
|
||||
x += pbf.readSVarint();
|
||||
y += pbf.readSVarint();
|
||||
if (x < x1) x1 = x;
|
||||
if (x > x2) x2 = x;
|
||||
if (y < y1) y1 = y;
|
||||
if (y > y2) y2 = y;
|
||||
|
||||
} else if (cmd !== 7) {
|
||||
throw new Error('unknown command ' + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
return [x1, y1, x2, y2];
|
||||
}
|
||||
|
||||
toGeoJSON(x = 0, y = 0, z = 1) {
|
||||
var size = this.extent * Math.pow(2, z),
|
||||
x0 = this.extent * x,
|
||||
y0 = this.extent * y,
|
||||
coords = this.loadGeometry(),
|
||||
type = this.types()[this.type],
|
||||
i, j;
|
||||
|
||||
function project(line) {
|
||||
for (var j = 0; j < line.length; j++) {
|
||||
var p = line[j]
|
||||
let y2 = 180 - (p.y + y0) * 360 / size;
|
||||
line[j] = [
|
||||
(p.x + x0) * 360 / size - 180,
|
||||
360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.type) {
|
||||
case 1:
|
||||
var points = [];
|
||||
for (i = 0; i < coords.length; i++) {
|
||||
points[i] = coords[i][0];
|
||||
}
|
||||
coords = points;
|
||||
project(coords);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (i = 0; i < coords.length; i++) {
|
||||
project(coords[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
coords = classifyRings(coords);
|
||||
for (i = 0; i < coords.length; i++) {
|
||||
for (j = 0; j < coords[i].length; j++) {
|
||||
project(coords[i][j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (coords.length === 1) {
|
||||
coords = coords[0];
|
||||
} else {
|
||||
type = 'Multi' + type;
|
||||
}
|
||||
|
||||
var result = {
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: type,
|
||||
coordinates: coords
|
||||
},
|
||||
properties: this.properties
|
||||
};
|
||||
|
||||
if ('id' in this) {
|
||||
result.id = this.id;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function readFeature(tag, feature, pbf) {
|
||||
if (tag == 1) feature.id = pbf.readVarint();
|
||||
else if (tag == 2) readTag(pbf, feature);
|
||||
else if (tag == 3) feature.type = pbf.readVarint();
|
||||
else if (tag == 4) feature._geometry = pbf.pos;
|
||||
}
|
||||
|
||||
function classifyRings(rings) {
|
||||
var len = rings.length;
|
||||
|
||||
if (len <= 1) return [rings];
|
||||
|
||||
var polygons = [],
|
||||
polygon,
|
||||
ccw;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
var area = signedArea(rings[i]);
|
||||
if (area === 0) continue;
|
||||
|
||||
if (ccw === undefined) ccw = area < 0;
|
||||
|
||||
if (ccw === area < 0) {
|
||||
if (polygon) polygons.push(polygon);
|
||||
polygon = [rings[i]];
|
||||
|
||||
} else {
|
||||
polygon.push(rings[i]);
|
||||
}
|
||||
}
|
||||
if (polygon) polygons.push(polygon);
|
||||
|
||||
return polygons;
|
||||
}
|
||||
|
||||
function signedArea(ring) {
|
||||
var sum = 0;
|
||||
for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
|
||||
p1 = ring[i];
|
||||
p2 = ring[j];
|
||||
sum += (p2.x - p1.x) * (p1.y + p2.y);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
function readTag(pbf, feature) {
|
||||
var end = pbf.readVarint() + pbf.pos;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
var key = feature._keys[pbf.readVarint()],
|
||||
value = feature._values[pbf.readVarint()];
|
||||
feature.properties[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
class TileLayer {
|
||||
constructor(pbf, end) {
|
||||
// Public
|
||||
this.version = 1;
|
||||
this.name = null;
|
||||
this.extent = 4096;
|
||||
this.length = 0;
|
||||
|
||||
// Private
|
||||
this._pbf = pbf;
|
||||
this._keys = [];
|
||||
this._values = [];
|
||||
this._features = [];
|
||||
|
||||
pbf.readFields(readLayer, this, end);
|
||||
|
||||
this.length = this._features.length;
|
||||
}
|
||||
|
||||
feature(i) {
|
||||
if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
|
||||
|
||||
this._pbf.pos = this._features[i];
|
||||
|
||||
var end = this._pbf.readVarint() + this._pbf.pos;
|
||||
return new TileFeature(this._pbf, end, this.extent, this._keys, this._values);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
function readLayer(tag, layer, pbf) {
|
||||
if (tag === 15) layer.version = pbf.readVarint();
|
||||
else if (tag === 1) layer.name = pbf.readString();
|
||||
else if (tag === 5) layer.extent = pbf.readVarint();
|
||||
else if (tag === 2) layer._features.push(pbf.pos);
|
||||
else if (tag === 3) layer._keys.push(pbf.readString());
|
||||
else if (tag === 4) layer._values.push(readValueMessage(pbf));
|
||||
}
|
||||
|
||||
function readValueMessage(pbf) {
|
||||
var value = null,
|
||||
end = pbf.readVarint() + pbf.pos;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
var tag = pbf.readVarint() >> 3;
|
||||
|
||||
value = tag === 1 ? pbf.readString() :
|
||||
tag === 2 ? pbf.readFloat() :
|
||||
tag === 3 ? pbf.readDouble() :
|
||||
tag === 4 ? pbf.readVarint64() :
|
||||
tag === 5 ? pbf.readVarint() :
|
||||
tag === 6 ? pbf.readSVarint() :
|
||||
tag === 7 ? pbf.readBoolean() : null;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
class VectorTile {
|
||||
constructor(pbf_tile) {
|
||||
this.pbf_tile = pbf_tile
|
||||
this.layers = {}
|
||||
}
|
||||
|
||||
features() {
|
||||
let jsonArray = []
|
||||
for (let layersKey in this.layers) {
|
||||
for (let i = 0; i < tile.layers[layersKey]._features.length; i++) {
|
||||
let json = this.layers[layersKey].feature(i).toGeoJSON()
|
||||
jsonArray.push(json)
|
||||
}
|
||||
}
|
||||
return jsonArray
|
||||
}
|
||||
|
||||
async on() {
|
||||
let res = await fetch(this.pbf_tile)
|
||||
let buf = await res.arrayBuffer()
|
||||
buf = new Uint8Array(buf)
|
||||
let pbf = new Pbf(buf)
|
||||
this.layers = pbf.readFields(this.readTile, {})
|
||||
}
|
||||
|
||||
readTile(tag, layers, pbf) {
|
||||
if (tag === 3) {
|
||||
var layer = new TileLayer(pbf, pbf.readVarint() + pbf.pos);
|
||||
if (layer.length) layers[layer.name] = layer;
|
||||
}
|
||||
}
|
||||
}
|
302
example/js/video.js
Normal file
302
example/js/video.js
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user