canvas-size
Version:
Determine the maximum area, height, width, and custom dimensions of an HTML canvas element.
404 lines (403 loc) • 17 kB
JavaScript
/*!
* canvas-size
* v2.0.0
* https://github.com/jhildenbiddle/canvas-size
* (c) 2015-2024 John Hildenbiddle <http://hildenbiddle.com>
* MIT license
*/
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self,
global.canvasSize = factory());
})(this, (function() {
"use strict";
function _iterableToArrayLimit(r, l) {
var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
if (null != t) {
var e, n, i, u, a = [], f = !0, o = !1;
try {
if (i = (t = t.call(r)).next, 0 === l) {
if (Object(t) !== t) return;
f = !1;
} else for (;!(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0) ;
} catch (r) {
o = !0, n = r;
} finally {
try {
if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return;
} finally {
if (o) throw n;
}
}
return a;
}
}
function ownKeys(e, r) {
var t = Object.keys(e);
if (Object.getOwnPropertySymbols) {
var o = Object.getOwnPropertySymbols(e);
r && (o = o.filter((function(r) {
return Object.getOwnPropertyDescriptor(e, r).enumerable;
}))), t.push.apply(t, o);
}
return t;
}
function _objectSpread2(e) {
for (var r = 1; r < arguments.length; r++) {
var t = null != arguments[r] ? arguments[r] : {};
r % 2 ? ownKeys(Object(t), !0).forEach((function(r) {
_defineProperty(e, r, t[r]);
})) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach((function(r) {
Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
}));
}
return e;
}
function _toPrimitive(t, r) {
if ("object" != typeof t || !t) return t;
var e = t[Symbol.toPrimitive];
if (void 0 !== e) {
var i = e.call(t, r || "default");
if ("object" != typeof i) return i;
throw new TypeError("@@toPrimitive must return a primitive value.");
}
return ("string" === r ? String : Number)(t);
}
function _toPropertyKey(t) {
var i = _toPrimitive(t, "string");
return "symbol" == typeof i ? i : String(i);
}
function _defineProperty(obj, key, value) {
key = _toPropertyKey(key);
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
function _objectWithoutPropertiesLoose(source, excluded) {
if (source == null) return {};
var target = {};
var sourceKeys = Object.keys(source);
var key, i;
for (i = 0; i < sourceKeys.length; i++) {
key = sourceKeys[i];
if (excluded.indexOf(key) >= 0) continue;
target[key] = source[key];
}
return target;
}
function _objectWithoutProperties(source, excluded) {
if (source == null) return {};
var target = _objectWithoutPropertiesLoose(source, excluded);
var key, i;
if (Object.getOwnPropertySymbols) {
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
for (i = 0; i < sourceSymbolKeys.length; i++) {
key = sourceSymbolKeys[i];
if (excluded.indexOf(key) >= 0) continue;
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
target[key] = source[key];
}
}
return target;
}
function _slicedToArray(arr, i) {
return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
}
function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _arrayWithHoles(arr) {
if (Array.isArray(arr)) return arr;
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _nonIterableRest() {
throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function canvasTest(settings) {
var size = settings.sizes.shift();
var width = Math.max(Math.ceil(size[0]), 1);
var height = Math.max(Math.ceil(size[1]), 1);
var fill = [ width - 1, height - 1, 1, 1 ];
var testTimeStart = performance.now();
var isWorker = typeof WorkerGlobalScope !== "undefined" && self instanceof WorkerGlobalScope;
var cropCvs, testCvs;
if (isWorker) {
cropCvs = new OffscreenCanvas(1, 1);
testCvs = new OffscreenCanvas(width, height);
} else {
cropCvs = document.createElement("canvas");
cropCvs.width = 1;
cropCvs.height = 1;
testCvs = document.createElement("canvas");
testCvs.width = width;
testCvs.height = height;
}
var cropCtx = cropCvs.getContext("2d");
var testCtx = testCvs.getContext("2d");
if (testCtx) {
testCtx.fillRect.apply(testCtx, fill);
cropCtx.drawImage(testCvs, width - 1, height - 1, 1, 1, 0, 0, 1, 1);
}
var isTestPass = cropCtx && cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0;
var testTime = parseInt(performance.now() - testTimeStart);
[ cropCvs, testCvs ].forEach((function(cvs) {
cvs.height = 0;
cvs.width = 0;
}));
if (isWorker) {
postMessage({
width: width,
height: height,
testTime: testTime,
isTestPass: isTestPass
});
if (!isTestPass && settings.sizes.length) {
setTimeout((function() {
canvasTest(settings);
}), 0);
}
} else if (isTestPass) {
settings.onSuccess({
width: width,
height: height,
testTime: testTime
});
} else {
settings.onError({
width: width,
height: height,
testTime: testTime
});
if (settings.sizes.length) {
setTimeout((function() {
canvasTest(settings);
}), 0);
}
}
return isTestPass;
}
var testSizes = {
area: [ 16384, 14188, 11402, 11180, 10836, 8192, 4096, 1 ],
height: [ 8388607, 65535, 32767, 16384, 8192, 4096, 1 ],
width: [ 4194303, 65535, 32767, 16384, 8192, 4096, 1 ]
};
var _excluded = [ "onError", "onSuccess" ];
var defaults = {
max: null,
min: 1,
sizes: [],
step: 1024,
useWorker: false,
onError: Function.prototype,
onSuccess: Function.prototype
};
var workerJobs = {};
function createSizesArray(settings) {
var isArea = settings.width === settings.height;
var isWidth = settings.height === 1;
var isHeight = settings.width === 1;
var sizes = [];
if (!settings.width || !settings.height) {
settings.sizes.forEach((function(testSize) {
var width = isArea || isWidth ? testSize : 1;
var height = isArea || isHeight ? testSize : 1;
sizes.push([ width, height ]);
}));
} else {
var testMin = settings.min || defaults.min;
var testStep = settings.step || defaults.step;
var testSize = Math.max(settings.width, settings.height);
while (testSize >= testMin) {
var width = isArea || isWidth ? testSize : 1;
var height = isArea || isHeight ? testSize : 1;
sizes.push([ width, height ]);
testSize -= testStep;
}
}
return sizes;
}
function handleMethod(settings) {
var isBrowser = typeof window !== "undefined";
var hasPromiseSupport = isBrowser && "Promise" in window;
var hasCanvasSupport = isBrowser && "HTMLCanvasElement" in window;
var hasOffscreenCanvasSupport = isBrowser && "OffscreenCanvas" in window;
var jobID = URL.createObjectURL(new Blob([])).slice(-36);
var totalTimeStart = performance.now();
var _onError = settings.onError, _onSuccess = settings.onSuccess, settingsWithoutCallbacks = _objectWithoutProperties(settings, _excluded);
var getTotalTime = function getTotalTime() {
return parseInt(performance.now() - totalTimeStart);
};
var worker = null;
if (!hasCanvasSupport) {
return false;
}
if (settings.useWorker && hasOffscreenCanvasSupport) {
var js = "\n var canvasTest = ".concat(canvasTest.toString(), ";\n onmessage = function(e) {\n canvasTest(e.data);\n };\n ");
var blob = new Blob([ js ], {
type: "application/javascript"
});
var blobURL = URL.createObjectURL(blob);
worker = new Worker(blobURL);
URL.revokeObjectURL(blobURL);
worker.onmessage = function(e) {
var _e$data = e.data, width = _e$data.width, height = _e$data.height, testTime = _e$data.testTime, isTestPass = _e$data.isTestPass;
var results = {
width: width,
height: height,
testTime: testTime,
totalTime: getTotalTime()
};
if (isTestPass) {
workerJobs[jobID].onSuccess(results);
delete workerJobs[jobID];
} else {
workerJobs[jobID].onError(results);
}
};
}
if (hasPromiseSupport) {
return new Promise((function(resolve) {
var promiseSettings = _objectSpread2(_objectSpread2({}, settings), {}, {
onError: function onError(_ref) {
var width = _ref.width, height = _ref.height, testTime = _ref.testTime;
var results = {
width: width,
height: height,
testTime: testTime,
totalTime: getTotalTime()
};
var isLastTest;
if (settings.sizes.length === 0) {
isLastTest = true;
} else {
var _settings$sizes$slice = settings.sizes.slice(-1), _settings$sizes$slice2 = _slicedToArray(_settings$sizes$slice, 1), _settings$sizes$slice3 = _slicedToArray(_settings$sizes$slice2[0], 2), lastWidth = _settings$sizes$slice3[0], lastHeight = _settings$sizes$slice3[1];
isLastTest = width === lastWidth && height === lastHeight;
}
_onError(results);
if (isLastTest) {
resolve(_objectSpread2(_objectSpread2({}, results), {}, {
success: false
}));
}
},
onSuccess: function onSuccess(_ref2) {
var width = _ref2.width, height = _ref2.height, testTime = _ref2.testTime;
var results = {
width: width,
height: height,
testTime: testTime,
totalTime: getTotalTime()
};
_onSuccess(results);
resolve(_objectSpread2(_objectSpread2({}, results), {}, {
success: true
}));
}
});
if (worker) {
var onError = promiseSettings.onError, onSuccess = promiseSettings.onSuccess;
workerJobs[jobID] = {
onError: onError,
onSuccess: onSuccess
};
worker.postMessage(settingsWithoutCallbacks);
} else {
canvasTest(promiseSettings);
}
}));
} else {
if (worker) {
workerJobs[jobID] = {
onError: _onError,
onSuccess: _onSuccess
};
worker.postMessage(settingsWithoutCallbacks);
} else {
return canvasTest(settings);
}
}
}
var canvasSize = {
maxArea: function maxArea() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var sizes = createSizesArray({
width: options.max,
height: options.max,
min: options.min,
step: options.step,
sizes: _toConsumableArray(testSizes.area)
});
var settings = _objectSpread2(_objectSpread2(_objectSpread2({}, defaults), options), {}, {
sizes: sizes
});
return handleMethod(settings);
},
maxHeight: function maxHeight() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var sizes = createSizesArray({
width: 1,
height: options.max,
min: options.min,
step: options.step,
sizes: _toConsumableArray(testSizes.height)
});
var settings = _objectSpread2(_objectSpread2(_objectSpread2({}, defaults), options), {}, {
sizes: sizes
});
return handleMethod(settings);
},
maxWidth: function maxWidth() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var sizes = createSizesArray({
width: options.max,
height: 1,
min: options.min,
step: options.step,
sizes: _toConsumableArray(testSizes.width)
});
var settings = _objectSpread2(_objectSpread2(_objectSpread2({}, defaults), options), {}, {
sizes: sizes
});
return handleMethod(settings);
},
test: function test() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var settings = _objectSpread2(_objectSpread2({}, defaults), options);
settings.sizes = _toConsumableArray(settings.sizes);
if (settings.width && settings.height) {
settings.sizes = [ [ settings.width, settings.height ] ];
}
return handleMethod(settings);
}
};
return canvasSize;
}));
//# sourceMappingURL=canvas-size.js.map