mirror of
https://github.com/liabru/matter-js.git
synced 2024-12-23 13:19:01 -05:00
add demo build config and refactor demo
This commit is contained in:
parent
f4d72ba3e4
commit
653a647e94
23 changed files with 28480 additions and 26023 deletions
|
@ -67,6 +67,7 @@
|
|||
"Metrics": false,
|
||||
"Example": false,
|
||||
"__MATTER_VERSION__": false,
|
||||
"__MATTER_IS_DEV__": false,
|
||||
"jest": false,
|
||||
"test": false,
|
||||
"expect": false,
|
||||
|
|
|
@ -7,4 +7,5 @@ install:
|
|||
script:
|
||||
- npm run lint
|
||||
- npm run test
|
||||
- npm run build
|
||||
- npm run build
|
||||
- npm run build-demo
|
|
@ -18,7 +18,7 @@ To build you must first install [node.js](http://nodejs.org), then run
|
|||
|
||||
which will install the required build dependencies, then run
|
||||
|
||||
npm run dev
|
||||
npm start
|
||||
|
||||
which will run the development server and opens `http://localhost:8000/` in your browser. Any changes you make to the source will automatically rebuild and reload the page.
|
||||
|
||||
|
@ -36,13 +36,15 @@ The output of `npm run test` also includes a [comparison report](https://github.
|
|||
|
||||
The following development commands can be run at the terminal
|
||||
|
||||
- **npm run dev**
|
||||
runs development server
|
||||
- **npm start**
|
||||
runs development server and opens demo page
|
||||
- **npm run build**
|
||||
creates a release build
|
||||
- **npm run build-demo**
|
||||
builds the demo
|
||||
- **npm run lint**
|
||||
runs the linter
|
||||
- **npm run test**
|
||||
- **npm run test**
|
||||
runs the tests and compares results
|
||||
- **npm run test-browser**
|
||||
runs the browser tests
|
||||
|
|
|
@ -1,179 +0,0 @@
|
|||
/**
|
||||
* A Matter.js build comparison testbed.
|
||||
*
|
||||
* Tool for Matter.js maintainers to compare results of
|
||||
* the current source build with the release build in the browser.
|
||||
*
|
||||
* USAGE: open http://localhost:8000/?compare=120#mixed
|
||||
*
|
||||
* NOTE: For the actual example code, refer to the source files in `/examples/`.
|
||||
*
|
||||
* @class Compare
|
||||
*/
|
||||
|
||||
(function() {
|
||||
// maintain reference to dev version of Matter already loaded
|
||||
var MatterDev = window.Matter;
|
||||
|
||||
// load the build version of Matter
|
||||
var matterBuildScript = document.createElement('script');
|
||||
matterBuildScript.src = '../build/matter.min.js';
|
||||
|
||||
// wait for load
|
||||
matterBuildScript.addEventListener('load', function() {
|
||||
var examples = window.MatterDemo.examples;
|
||||
|
||||
// maintain reference of build version and set dev version as main
|
||||
var MatterBuild = window.Matter;
|
||||
window.Matter = MatterDev;
|
||||
|
||||
var demo = MatterTools.Demo.create({
|
||||
toolbar: {
|
||||
title: 'matter-js',
|
||||
url: 'https://github.com/liabru/matter-js',
|
||||
reset: true,
|
||||
source: true,
|
||||
inspector: true,
|
||||
tools: true,
|
||||
fullscreen: true,
|
||||
exampleSelect: true
|
||||
},
|
||||
tools: {
|
||||
inspector: true,
|
||||
gui: true
|
||||
},
|
||||
inline: false,
|
||||
preventZoom: true,
|
||||
resetOnOrientation: true,
|
||||
routing: true,
|
||||
startExample: 'mixed',
|
||||
examples: examples
|
||||
});
|
||||
|
||||
var demoBuild = MatterTools.Demo.create({
|
||||
toolbar: {
|
||||
title: 'matter-js-compare-build',
|
||||
reset: false,
|
||||
source: false,
|
||||
inspector: false,
|
||||
tools: false,
|
||||
fullscreen: false,
|
||||
exampleSelect: false
|
||||
},
|
||||
tools: {
|
||||
inspector: false,
|
||||
gui: false
|
||||
},
|
||||
inline: false,
|
||||
preventZoom: true,
|
||||
resetOnOrientation: true,
|
||||
routing: false,
|
||||
startExample: 'mixed',
|
||||
examples: examples.map(function(example) {
|
||||
return Matter.Common.extend({}, example);
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* NOTE: For the actual example code, refer to the source files in `/examples/`.
|
||||
* The code below is tooling for Matter.js maintainers to compare versions of Matter.
|
||||
*/
|
||||
|
||||
// build version should not run itself
|
||||
MatterBuild.Runner.run = function() {};
|
||||
MatterBuild.Render.run = function() {};
|
||||
|
||||
// maintain original references to patched methods
|
||||
MatterDev.Runner._tick = MatterDev.Runner.tick;
|
||||
MatterDev.Render._world = MatterDev.Render.world;
|
||||
MatterBuild.Mouse._setElement = MatterBuild.Mouse.setElement;
|
||||
|
||||
// patch MatterTools to control both demo versions simultaneously
|
||||
MatterTools.Demo._setExample = MatterTools.Demo.setExample;
|
||||
MatterTools.Demo.setExample = function(_demo, example) {
|
||||
MatterBuild.Common._nextId = MatterBuild.Common._seed = 0;
|
||||
MatterDev.Common._nextId = MatterDev.Common._seed = 0;
|
||||
|
||||
MatterBuild.Plugin._registry = MatterDev.Plugin._registry;
|
||||
MatterBuild.use.apply(null, MatterDev.used);
|
||||
|
||||
window.Matter = MatterDev;
|
||||
MatterTools.Demo._setExample(
|
||||
demo, demo.examples.find(function(e) { return e.name === example.name; })
|
||||
);
|
||||
|
||||
var maxTicks = parseFloat(window.location.search.split('=')[1]);
|
||||
var ticks = 0;
|
||||
|
||||
MatterDev.Runner.tick = function(runner, engine, time) {
|
||||
if (ticks === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ticks >= maxTicks) {
|
||||
console.info(
|
||||
'Demo.Compare: ran ' + ticks + ' ticks, timestamp is now '
|
||||
+ engine.timing.timestamp.toFixed(2)
|
||||
);
|
||||
|
||||
ticks = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ticks += 1;
|
||||
|
||||
var demoBuildInstance = demoBuild.example.instance;
|
||||
runner.isFixed = demoBuildInstance.runner.isFixed = true;
|
||||
runner.delta = demoBuildInstance.runner.delta = 1000 / 60;
|
||||
|
||||
window.Matter = MatterBuild;
|
||||
MatterBuild.Runner.tick(demoBuildInstance.runner, demoBuildInstance.engine, time);
|
||||
window.Matter = MatterDev;
|
||||
return MatterDev.Runner._tick(runner, engine, time);
|
||||
};
|
||||
|
||||
MatterDev.Render.world = function(render) {
|
||||
window.Matter = MatterBuild;
|
||||
MatterBuild.Render.world(demoBuild.example.instance.render);
|
||||
window.Matter = MatterDev;
|
||||
return MatterDev.Render._world(render);
|
||||
};
|
||||
|
||||
MatterBuild.Mouse.setElement = function(mouse) {
|
||||
return MatterBuild.Mouse._setElement(mouse, demo.example.instance.render.canvas);
|
||||
};
|
||||
|
||||
window.Matter = MatterBuild;
|
||||
MatterTools.Demo._setExample(
|
||||
demoBuild, demoBuild.examples.find(function(e) { return e.name === example.name; })
|
||||
);
|
||||
|
||||
window.Matter = MatterDev;
|
||||
};
|
||||
|
||||
// reset both engine versions simultaneously
|
||||
MatterTools.Demo._reset = MatterTools.Demo.reset;
|
||||
MatterTools.Demo.reset = function(_demo) {
|
||||
MatterBuild.Common._nextId = MatterBuild.Common._seed = 0;
|
||||
MatterDev.Common._nextId = MatterDev.Common._seed = 0;
|
||||
|
||||
window.Matter = MatterBuild;
|
||||
MatterTools.Demo._reset(demoBuild);
|
||||
|
||||
window.Matter = MatterDev;
|
||||
MatterTools.Demo._reset(demo);
|
||||
};
|
||||
|
||||
document.body.appendChild(demo.dom.root);
|
||||
document.body.appendChild(demoBuild.dom.root);
|
||||
|
||||
MatterTools.Demo.start(demo);
|
||||
|
||||
console.info(
|
||||
'Demo.Compare: comparing matter-js@' + MatterDev.version + ' with matter-js@' + MatterBuild.version
|
||||
);
|
||||
});
|
||||
|
||||
document.body.append(matterBuildScript);
|
||||
})();
|
107
demo/js/Demo.js
107
demo/js/Demo.js
|
@ -1,107 +0,0 @@
|
|||
/**
|
||||
* The Matter.js development demo and testing tool.
|
||||
*
|
||||
* This demo uses MatterTools, you can see the wiki for a simple example instead:
|
||||
* https://github.com/liabru/matter-js/wiki/Getting-started
|
||||
*
|
||||
* NOTE: For the actual example code, refer to the source files in `/examples/`.
|
||||
*
|
||||
* @class Demo
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var examples = [
|
||||
{ name: 'Air Friction', id: 'airFriction' },
|
||||
{ name: 'Avalanche', id: 'avalanche' },
|
||||
{ name: 'Ball Pool', id: 'ballPool' },
|
||||
{ name: 'Bridge', id: 'bridge' },
|
||||
{ name: 'Broadphase', id: 'broadphase' },
|
||||
{ name: 'Car', id: 'car' },
|
||||
{ name: 'Catapult', id: 'catapult' },
|
||||
{ name: 'Chains', id: 'chains' },
|
||||
{ name: 'Circle Stack', id: 'circleStack' },
|
||||
{ name: 'Cloth', id: 'cloth' },
|
||||
{ name: 'Collision Filtering', id: 'collisionFiltering' },
|
||||
{ name: 'Composite Manipulation', id: 'compositeManipulation' },
|
||||
{ name: 'Compound Bodies', id: 'compound' },
|
||||
{ name: 'Compound Stack', id: 'compoundStack' },
|
||||
{ name: 'Concave', id: 'concave' },
|
||||
{ name: 'Constraints', id: 'constraints' },
|
||||
{ name: 'Double Pendulum', id: 'doublePendulum' },
|
||||
{ name: 'Events', id: 'events' },
|
||||
{ name: 'Friction', id: 'friction' },
|
||||
{ name: 'Reverse Gravity', id: 'gravity' },
|
||||
{ name: 'Gyroscope', id: 'gyro' },
|
||||
{ name: 'Manipulation', id: 'manipulation' },
|
||||
{ name: 'Mixed Shapes', id: 'mixed' },
|
||||
{ name: 'Newton\'s Cradle', id: 'newtonsCradle' },
|
||||
{ name: 'Ragdoll', id: 'ragdoll' },
|
||||
{ name: 'Pyramid', id: 'pyramid' },
|
||||
{ name: 'Raycasting', id: 'raycasting' },
|
||||
{ name: 'Restitution', id: 'restitution' },
|
||||
{ name: 'Rounded Corners (Chamfering)', id: 'rounded' },
|
||||
{ name: 'Sensors', id: 'sensors' },
|
||||
{ name: 'Sleeping', id: 'sleeping' },
|
||||
{ name: 'Slingshot', id: 'slingshot' },
|
||||
{ name: 'Soft Body', id: 'softBody' },
|
||||
{ name: 'Sprites', id: 'sprites' },
|
||||
{ name: 'Stack', id: 'stack' },
|
||||
{ name: 'Static Friction', id: 'staticFriction' },
|
||||
{ name: 'Stress', id: 'stress' },
|
||||
{ name: 'Stress 2', id: 'stress2' },
|
||||
{ name: 'Concave SVG Paths', id: 'svg' },
|
||||
{ name: 'Terrain', id: 'terrain' },
|
||||
{ name: 'Time Scaling', id: 'timescale' },
|
||||
{ name: 'Views', id: 'views' },
|
||||
{ name: 'Wrecking Ball', id: 'wreckingBall' }
|
||||
];
|
||||
|
||||
var sourceLinkRoot = 'https://github.com/liabru/matter-js/blob/master/examples';
|
||||
|
||||
for (var i = 0; i < examples.length; i += 1) {
|
||||
var example = examples[i];
|
||||
example.sourceLink = sourceLinkRoot + '/' + example.id + '.js';
|
||||
example.init = window.Example[example.id];
|
||||
|
||||
if (!example.init) {
|
||||
console.warn('Example not loaded:', example.id);
|
||||
}
|
||||
}
|
||||
|
||||
if (window.location.search.indexOf('compare') >= 0) {
|
||||
var compareScript = document.createElement('script');
|
||||
compareScript.src = '../js/Compare.js';
|
||||
window.MatterDemo = { examples: examples };
|
||||
document.body.append(compareScript);
|
||||
return;
|
||||
}
|
||||
|
||||
var demo = MatterTools.Demo.create({
|
||||
toolbar: {
|
||||
title: 'matter-js',
|
||||
url: 'https://github.com/liabru/matter-js',
|
||||
reset: true,
|
||||
source: true,
|
||||
inspector: true,
|
||||
tools: true,
|
||||
fullscreen: true,
|
||||
exampleSelect: true
|
||||
},
|
||||
tools: {
|
||||
inspector: true,
|
||||
gui: true
|
||||
},
|
||||
inline: false,
|
||||
preventZoom: true,
|
||||
resetOnOrientation: true,
|
||||
routing: true,
|
||||
startExample: 'mixed',
|
||||
examples: examples
|
||||
});
|
||||
|
||||
window.MatterDemo = demo;
|
||||
|
||||
document.body.appendChild(demo.dom.root);
|
||||
|
||||
MatterTools.Demo.start(demo);
|
||||
})();
|
5863
demo/js/Examples.js
5863
demo/js/Examples.js
File diff suppressed because it is too large
Load diff
|
@ -1,3 +0,0 @@
|
|||
// bundle entry point for the development server
|
||||
Example = require('../../examples/index.js');
|
||||
module.exports = require('../../src/module/main.js');
|
|
@ -1,662 +0,0 @@
|
|||
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.decomp=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
|
||||
module.exports = {
|
||||
decomp: polygonDecomp,
|
||||
quickDecomp: polygonQuickDecomp,
|
||||
isSimple: polygonIsSimple,
|
||||
removeCollinearPoints: polygonRemoveCollinearPoints,
|
||||
removeDuplicatePoints: polygonRemoveDuplicatePoints,
|
||||
makeCCW: polygonMakeCCW
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the intersection between two lines.
|
||||
* @static
|
||||
* @method lineInt
|
||||
* @param {Array} l1 Line vector 1
|
||||
* @param {Array} l2 Line vector 2
|
||||
* @param {Number} precision Precision to use when checking if the lines are parallel
|
||||
* @return {Array} The intersection point.
|
||||
*/
|
||||
function lineInt(l1,l2,precision){
|
||||
precision = precision || 0;
|
||||
var i = [0,0]; // point
|
||||
var a1, b1, c1, a2, b2, c2, det; // scalars
|
||||
a1 = l1[1][1] - l1[0][1];
|
||||
b1 = l1[0][0] - l1[1][0];
|
||||
c1 = a1 * l1[0][0] + b1 * l1[0][1];
|
||||
a2 = l2[1][1] - l2[0][1];
|
||||
b2 = l2[0][0] - l2[1][0];
|
||||
c2 = a2 * l2[0][0] + b2 * l2[0][1];
|
||||
det = a1 * b2 - a2*b1;
|
||||
if (!scalar_eq(det, 0, precision)) { // lines are not parallel
|
||||
i[0] = (b2 * c1 - b1 * c2) / det;
|
||||
i[1] = (a1 * c2 - a2 * c1) / det;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if two line segments intersects.
|
||||
* @method segmentsIntersect
|
||||
* @param {Array} p1 The start vertex of the first line segment.
|
||||
* @param {Array} p2 The end vertex of the first line segment.
|
||||
* @param {Array} q1 The start vertex of the second line segment.
|
||||
* @param {Array} q2 The end vertex of the second line segment.
|
||||
* @return {Boolean} True if the two line segments intersect
|
||||
*/
|
||||
function lineSegmentsIntersect(p1, p2, q1, q2){
|
||||
var dx = p2[0] - p1[0];
|
||||
var dy = p2[1] - p1[1];
|
||||
var da = q2[0] - q1[0];
|
||||
var db = q2[1] - q1[1];
|
||||
|
||||
// segments are parallel
|
||||
if((da*dy - db*dx) === 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
var s = (dx * (q1[1] - p1[1]) + dy * (p1[0] - q1[0])) / (da * dy - db * dx);
|
||||
var t = (da * (p1[1] - q1[1]) + db * (q1[0] - p1[0])) / (db * dx - da * dy);
|
||||
|
||||
return (s>=0 && s<=1 && t>=0 && t<=1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the area of a triangle spanned by the three given points. Note that the area will be negative if the points are not given in counter-clockwise order.
|
||||
* @static
|
||||
* @method area
|
||||
* @param {Array} a
|
||||
* @param {Array} b
|
||||
* @param {Array} c
|
||||
* @return {Number}
|
||||
*/
|
||||
function triangleArea(a,b,c){
|
||||
return (((b[0] - a[0])*(c[1] - a[1]))-((c[0] - a[0])*(b[1] - a[1])));
|
||||
}
|
||||
|
||||
function isLeft(a,b,c){
|
||||
return triangleArea(a,b,c) > 0;
|
||||
}
|
||||
|
||||
function isLeftOn(a,b,c) {
|
||||
return triangleArea(a, b, c) >= 0;
|
||||
}
|
||||
|
||||
function isRight(a,b,c) {
|
||||
return triangleArea(a, b, c) < 0;
|
||||
}
|
||||
|
||||
function isRightOn(a,b,c) {
|
||||
return triangleArea(a, b, c) <= 0;
|
||||
}
|
||||
|
||||
var tmpPoint1 = [],
|
||||
tmpPoint2 = [];
|
||||
|
||||
/**
|
||||
* Check if three points are collinear
|
||||
* @method collinear
|
||||
* @param {Array} a
|
||||
* @param {Array} b
|
||||
* @param {Array} c
|
||||
* @param {Number} [thresholdAngle=0] Threshold angle to use when comparing the vectors. The function will return true if the angle between the resulting vectors is less than this value. Use zero for max precision.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function collinear(a,b,c,thresholdAngle) {
|
||||
if(!thresholdAngle){
|
||||
return triangleArea(a, b, c) === 0;
|
||||
} else {
|
||||
var ab = tmpPoint1,
|
||||
bc = tmpPoint2;
|
||||
|
||||
ab[0] = b[0]-a[0];
|
||||
ab[1] = b[1]-a[1];
|
||||
bc[0] = c[0]-b[0];
|
||||
bc[1] = c[1]-b[1];
|
||||
|
||||
var dot = ab[0]*bc[0] + ab[1]*bc[1],
|
||||
magA = Math.sqrt(ab[0]*ab[0] + ab[1]*ab[1]),
|
||||
magB = Math.sqrt(bc[0]*bc[0] + bc[1]*bc[1]),
|
||||
angle = Math.acos(dot/(magA*magB));
|
||||
return angle < thresholdAngle;
|
||||
}
|
||||
}
|
||||
|
||||
function sqdist(a,b){
|
||||
var dx = b[0] - a[0];
|
||||
var dy = b[1] - a[1];
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a vertex at position i. It does not matter if i is out of bounds, this function will just cycle.
|
||||
* @method at
|
||||
* @param {Number} i
|
||||
* @return {Array}
|
||||
*/
|
||||
function polygonAt(polygon, i){
|
||||
var s = polygon.length;
|
||||
return polygon[i < 0 ? i % s + s : i % s];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the polygon data
|
||||
* @method clear
|
||||
* @return {Array}
|
||||
*/
|
||||
function polygonClear(polygon){
|
||||
polygon.length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append points "from" to "to"-1 from an other polygon "poly" onto this one.
|
||||
* @method append
|
||||
* @param {Polygon} poly The polygon to get points from.
|
||||
* @param {Number} from The vertex index in "poly".
|
||||
* @param {Number} to The end vertex index in "poly". Note that this vertex is NOT included when appending.
|
||||
* @return {Array}
|
||||
*/
|
||||
function polygonAppend(polygon, poly, from, to){
|
||||
for(var i=from; i<to; i++){
|
||||
polygon.push(poly[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure that the polygon vertices are ordered counter-clockwise.
|
||||
* @method makeCCW
|
||||
*/
|
||||
function polygonMakeCCW(polygon){
|
||||
var br = 0,
|
||||
v = polygon;
|
||||
|
||||
// find bottom right point
|
||||
for (var i = 1; i < polygon.length; ++i) {
|
||||
if (v[i][1] < v[br][1] || (v[i][1] === v[br][1] && v[i][0] > v[br][0])) {
|
||||
br = i;
|
||||
}
|
||||
}
|
||||
|
||||
// reverse poly if clockwise
|
||||
if (!isLeft(polygonAt(polygon, br - 1), polygonAt(polygon, br), polygonAt(polygon, br + 1))) {
|
||||
polygonReverse(polygon);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the vertices in the polygon
|
||||
* @method reverse
|
||||
*/
|
||||
function polygonReverse(polygon){
|
||||
var tmp = [];
|
||||
var N = polygon.length;
|
||||
for(var i=0; i!==N; i++){
|
||||
tmp.push(polygon.pop());
|
||||
}
|
||||
for(var i=0; i!==N; i++){
|
||||
polygon[i] = tmp[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a point in the polygon is a reflex point
|
||||
* @method isReflex
|
||||
* @param {Number} i
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function polygonIsReflex(polygon, i){
|
||||
return isRight(polygonAt(polygon, i - 1), polygonAt(polygon, i), polygonAt(polygon, i + 1));
|
||||
}
|
||||
|
||||
var tmpLine1=[],
|
||||
tmpLine2=[];
|
||||
|
||||
/**
|
||||
* Check if two vertices in the polygon can see each other
|
||||
* @method canSee
|
||||
* @param {Number} a Vertex index 1
|
||||
* @param {Number} b Vertex index 2
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function polygonCanSee(polygon, a,b) {
|
||||
var p, dist, l1=tmpLine1, l2=tmpLine2;
|
||||
|
||||
if (isLeftOn(polygonAt(polygon, a + 1), polygonAt(polygon, a), polygonAt(polygon, b)) && isRightOn(polygonAt(polygon, a - 1), polygonAt(polygon, a), polygonAt(polygon, b))) {
|
||||
return false;
|
||||
}
|
||||
dist = sqdist(polygonAt(polygon, a), polygonAt(polygon, b));
|
||||
for (var i = 0; i !== polygon.length; ++i) { // for each edge
|
||||
if ((i + 1) % polygon.length === a || i === a){ // ignore incident edges
|
||||
continue;
|
||||
}
|
||||
if (isLeftOn(polygonAt(polygon, a), polygonAt(polygon, b), polygonAt(polygon, i + 1)) && isRightOn(polygonAt(polygon, a), polygonAt(polygon, b), polygonAt(polygon, i))) { // if diag intersects an edge
|
||||
l1[0] = polygonAt(polygon, a);
|
||||
l1[1] = polygonAt(polygon, b);
|
||||
l2[0] = polygonAt(polygon, i);
|
||||
l2[1] = polygonAt(polygon, i + 1);
|
||||
p = lineInt(l1,l2);
|
||||
if (sqdist(polygonAt(polygon, a), p) < dist) { // if edge is blocking visibility to b
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two vertices in the polygon can see each other
|
||||
* @method canSee2
|
||||
* @param {Number} a Vertex index 1
|
||||
* @param {Number} b Vertex index 2
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function polygonCanSee2(polygon, a,b) {
|
||||
// for each edge
|
||||
for (var i = 0; i !== polygon.length; ++i) {
|
||||
// ignore incident edges
|
||||
if (i === a || i === b || (i + 1) % polygon.length === a || (i + 1) % polygon.length === b){
|
||||
continue;
|
||||
}
|
||||
if( lineSegmentsIntersect(polygonAt(polygon, a), polygonAt(polygon, b), polygonAt(polygon, i), polygonAt(polygon, i+1)) ){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the polygon from vertex i to vertex j.
|
||||
* @method copy
|
||||
* @param {Number} i
|
||||
* @param {Number} j
|
||||
* @param {Polygon} [targetPoly] Optional target polygon to save in.
|
||||
* @return {Polygon} The resulting copy.
|
||||
*/
|
||||
function polygonCopy(polygon, i,j,targetPoly){
|
||||
var p = targetPoly || [];
|
||||
polygonClear(p);
|
||||
if (i < j) {
|
||||
// Insert all vertices from i to j
|
||||
for(var k=i; k<=j; k++){
|
||||
p.push(polygon[k]);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Insert vertices 0 to j
|
||||
for(var k=0; k<=j; k++){
|
||||
p.push(polygon[k]);
|
||||
}
|
||||
|
||||
// Insert vertices i to end
|
||||
for(var k=i; k<polygon.length; k++){
|
||||
p.push(polygon[k]);
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decomposes the polygon into convex pieces. Returns a list of edges [[p1,p2],[p2,p3],...] that cuts the polygon.
|
||||
* Note that this algorithm has complexity O(N^4) and will be very slow for polygons with many vertices.
|
||||
* @method getCutEdges
|
||||
* @return {Array}
|
||||
*/
|
||||
function polygonGetCutEdges(polygon) {
|
||||
var min=[], tmp1=[], tmp2=[], tmpPoly = [];
|
||||
var nDiags = Number.MAX_VALUE;
|
||||
|
||||
for (var i = 0; i < polygon.length; ++i) {
|
||||
if (polygonIsReflex(polygon, i)) {
|
||||
for (var j = 0; j < polygon.length; ++j) {
|
||||
if (polygonCanSee(polygon, i, j)) {
|
||||
tmp1 = polygonGetCutEdges(polygonCopy(polygon, i, j, tmpPoly));
|
||||
tmp2 = polygonGetCutEdges(polygonCopy(polygon, j, i, tmpPoly));
|
||||
|
||||
for(var k=0; k<tmp2.length; k++){
|
||||
tmp1.push(tmp2[k]);
|
||||
}
|
||||
|
||||
if (tmp1.length < nDiags) {
|
||||
min = tmp1;
|
||||
nDiags = tmp1.length;
|
||||
min.push([polygonAt(polygon, i), polygonAt(polygon, j)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decomposes the polygon into one or more convex sub-Polygons.
|
||||
* @method decomp
|
||||
* @return {Array} An array or Polygon objects.
|
||||
*/
|
||||
function polygonDecomp(polygon){
|
||||
var edges = polygonGetCutEdges(polygon);
|
||||
if(edges.length > 0){
|
||||
return polygonSlice(polygon, edges);
|
||||
} else {
|
||||
return [polygon];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Slices the polygon given one or more cut edges. If given one, this function will return two polygons (false on failure). If many, an array of polygons.
|
||||
* @method slice
|
||||
* @param {Array} cutEdges A list of edges, as returned by .getCutEdges()
|
||||
* @return {Array}
|
||||
*/
|
||||
function polygonSlice(polygon, cutEdges){
|
||||
if(cutEdges.length === 0){
|
||||
return [polygon];
|
||||
}
|
||||
if(cutEdges instanceof Array && cutEdges.length && cutEdges[0] instanceof Array && cutEdges[0].length===2 && cutEdges[0][0] instanceof Array){
|
||||
|
||||
var polys = [polygon];
|
||||
|
||||
for(var i=0; i<cutEdges.length; i++){
|
||||
var cutEdge = cutEdges[i];
|
||||
// Cut all polys
|
||||
for(var j=0; j<polys.length; j++){
|
||||
var poly = polys[j];
|
||||
var result = polygonSlice(poly, cutEdge);
|
||||
if(result){
|
||||
// Found poly! Cut and quit
|
||||
polys.splice(j,1);
|
||||
polys.push(result[0],result[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return polys;
|
||||
} else {
|
||||
|
||||
// Was given one edge
|
||||
var cutEdge = cutEdges;
|
||||
var i = polygon.indexOf(cutEdge[0]);
|
||||
var j = polygon.indexOf(cutEdge[1]);
|
||||
|
||||
if(i !== -1 && j !== -1){
|
||||
return [polygonCopy(polygon, i,j),
|
||||
polygonCopy(polygon, j,i)];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the line segments of this polygon do not intersect each other.
|
||||
* @method isSimple
|
||||
* @param {Array} path An array of vertices e.g. [[0,0],[0,1],...]
|
||||
* @return {Boolean}
|
||||
* @todo Should it check all segments with all others?
|
||||
*/
|
||||
function polygonIsSimple(polygon){
|
||||
var path = polygon, i;
|
||||
// Check
|
||||
for(i=0; i<path.length-1; i++){
|
||||
for(var j=0; j<i-1; j++){
|
||||
if(lineSegmentsIntersect(path[i], path[i+1], path[j], path[j+1] )){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check the segment between the last and the first point to all others
|
||||
for(i=1; i<path.length-2; i++){
|
||||
if(lineSegmentsIntersect(path[0], path[path.length-1], path[i], path[i+1] )){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function getIntersectionPoint(p1, p2, q1, q2, delta){
|
||||
delta = delta || 0;
|
||||
var a1 = p2[1] - p1[1];
|
||||
var b1 = p1[0] - p2[0];
|
||||
var c1 = (a1 * p1[0]) + (b1 * p1[1]);
|
||||
var a2 = q2[1] - q1[1];
|
||||
var b2 = q1[0] - q2[0];
|
||||
var c2 = (a2 * q1[0]) + (b2 * q1[1]);
|
||||
var det = (a1 * b2) - (a2 * b1);
|
||||
|
||||
if(!scalar_eq(det,0,delta)){
|
||||
return [((b2 * c1) - (b1 * c2)) / det, ((a1 * c2) - (a2 * c1)) / det];
|
||||
} else {
|
||||
return [0,0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quickly decompose the Polygon into convex sub-polygons.
|
||||
* @method quickDecomp
|
||||
* @param {Array} result
|
||||
* @param {Array} [reflexVertices]
|
||||
* @param {Array} [steinerPoints]
|
||||
* @param {Number} [delta]
|
||||
* @param {Number} [maxlevel]
|
||||
* @param {Number} [level]
|
||||
* @return {Array}
|
||||
*/
|
||||
function polygonQuickDecomp(polygon, result,reflexVertices,steinerPoints,delta,maxlevel,level){
|
||||
maxlevel = maxlevel || 100;
|
||||
level = level || 0;
|
||||
delta = delta || 25;
|
||||
result = typeof(result)!=="undefined" ? result : [];
|
||||
reflexVertices = reflexVertices || [];
|
||||
steinerPoints = steinerPoints || [];
|
||||
|
||||
var upperInt=[0,0], lowerInt=[0,0], p=[0,0]; // Points
|
||||
var upperDist=0, lowerDist=0, d=0, closestDist=0; // scalars
|
||||
var upperIndex=0, lowerIndex=0, closestIndex=0; // Integers
|
||||
var lowerPoly=[], upperPoly=[]; // polygons
|
||||
var poly = polygon,
|
||||
v = polygon;
|
||||
|
||||
if(v.length < 3){
|
||||
return result;
|
||||
}
|
||||
|
||||
level++;
|
||||
if(level > maxlevel){
|
||||
console.warn("quickDecomp: max level ("+maxlevel+") reached.");
|
||||
return result;
|
||||
}
|
||||
|
||||
for (var i = 0; i < polygon.length; ++i) {
|
||||
if (polygonIsReflex(poly, i)) {
|
||||
reflexVertices.push(poly[i]);
|
||||
upperDist = lowerDist = Number.MAX_VALUE;
|
||||
|
||||
|
||||
for (var j = 0; j < polygon.length; ++j) {
|
||||
if (isLeft(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j)) && isRightOn(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j - 1))) { // if line intersects with an edge
|
||||
p = getIntersectionPoint(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j), polygonAt(poly, j - 1)); // find the point of intersection
|
||||
if (isRight(polygonAt(poly, i + 1), polygonAt(poly, i), p)) { // make sure it's inside the poly
|
||||
d = sqdist(poly[i], p);
|
||||
if (d < lowerDist) { // keep only the closest intersection
|
||||
lowerDist = d;
|
||||
lowerInt = p;
|
||||
lowerIndex = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isLeft(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j + 1)) && isRightOn(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j))) {
|
||||
p = getIntersectionPoint(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j), polygonAt(poly, j + 1));
|
||||
if (isLeft(polygonAt(poly, i - 1), polygonAt(poly, i), p)) {
|
||||
d = sqdist(poly[i], p);
|
||||
if (d < upperDist) {
|
||||
upperDist = d;
|
||||
upperInt = p;
|
||||
upperIndex = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if there are no vertices to connect to, choose a point in the middle
|
||||
if (lowerIndex === (upperIndex + 1) % polygon.length) {
|
||||
//console.log("Case 1: Vertex("+i+"), lowerIndex("+lowerIndex+"), upperIndex("+upperIndex+"), poly.size("+polygon.length+")");
|
||||
p[0] = (lowerInt[0] + upperInt[0]) / 2;
|
||||
p[1] = (lowerInt[1] + upperInt[1]) / 2;
|
||||
steinerPoints.push(p);
|
||||
|
||||
if (i < upperIndex) {
|
||||
//lowerPoly.insert(lowerPoly.end(), poly.begin() + i, poly.begin() + upperIndex + 1);
|
||||
polygonAppend(lowerPoly, poly, i, upperIndex+1);
|
||||
lowerPoly.push(p);
|
||||
upperPoly.push(p);
|
||||
if (lowerIndex !== 0){
|
||||
//upperPoly.insert(upperPoly.end(), poly.begin() + lowerIndex, poly.end());
|
||||
polygonAppend(upperPoly, poly,lowerIndex,poly.length);
|
||||
}
|
||||
//upperPoly.insert(upperPoly.end(), poly.begin(), poly.begin() + i + 1);
|
||||
polygonAppend(upperPoly, poly,0,i+1);
|
||||
} else {
|
||||
if (i !== 0){
|
||||
//lowerPoly.insert(lowerPoly.end(), poly.begin() + i, poly.end());
|
||||
polygonAppend(lowerPoly, poly,i,poly.length);
|
||||
}
|
||||
//lowerPoly.insert(lowerPoly.end(), poly.begin(), poly.begin() + upperIndex + 1);
|
||||
polygonAppend(lowerPoly, poly,0,upperIndex+1);
|
||||
lowerPoly.push(p);
|
||||
upperPoly.push(p);
|
||||
//upperPoly.insert(upperPoly.end(), poly.begin() + lowerIndex, poly.begin() + i + 1);
|
||||
polygonAppend(upperPoly, poly,lowerIndex,i+1);
|
||||
}
|
||||
} else {
|
||||
// connect to the closest point within the triangle
|
||||
//console.log("Case 2: Vertex("+i+"), closestIndex("+closestIndex+"), poly.size("+polygon.length+")\n");
|
||||
|
||||
if (lowerIndex > upperIndex) {
|
||||
upperIndex += polygon.length;
|
||||
}
|
||||
closestDist = Number.MAX_VALUE;
|
||||
|
||||
if(upperIndex < lowerIndex){
|
||||
return result;
|
||||
}
|
||||
|
||||
for (var j = lowerIndex; j <= upperIndex; ++j) {
|
||||
if (
|
||||
isLeftOn(polygonAt(poly, i - 1), polygonAt(poly, i), polygonAt(poly, j)) &&
|
||||
isRightOn(polygonAt(poly, i + 1), polygonAt(poly, i), polygonAt(poly, j))
|
||||
) {
|
||||
d = sqdist(polygonAt(poly, i), polygonAt(poly, j));
|
||||
if (d < closestDist && polygonCanSee2(poly, i, j)) {
|
||||
closestDist = d;
|
||||
closestIndex = j % polygon.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i < closestIndex) {
|
||||
polygonAppend(lowerPoly, poly,i,closestIndex+1);
|
||||
if (closestIndex !== 0){
|
||||
polygonAppend(upperPoly, poly,closestIndex,v.length);
|
||||
}
|
||||
polygonAppend(upperPoly, poly,0,i+1);
|
||||
} else {
|
||||
if (i !== 0){
|
||||
polygonAppend(lowerPoly, poly,i,v.length);
|
||||
}
|
||||
polygonAppend(lowerPoly, poly,0,closestIndex+1);
|
||||
polygonAppend(upperPoly, poly,closestIndex,i+1);
|
||||
}
|
||||
}
|
||||
|
||||
// solve smallest poly first
|
||||
if (lowerPoly.length < upperPoly.length) {
|
||||
polygonQuickDecomp(lowerPoly,result,reflexVertices,steinerPoints,delta,maxlevel,level);
|
||||
polygonQuickDecomp(upperPoly,result,reflexVertices,steinerPoints,delta,maxlevel,level);
|
||||
} else {
|
||||
polygonQuickDecomp(upperPoly,result,reflexVertices,steinerPoints,delta,maxlevel,level);
|
||||
polygonQuickDecomp(lowerPoly,result,reflexVertices,steinerPoints,delta,maxlevel,level);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
result.push(polygon);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove collinear points in the polygon.
|
||||
* @method removeCollinearPoints
|
||||
* @param {Number} [precision] The threshold angle to use when determining whether two edges are collinear. Use zero for finest precision.
|
||||
* @return {Number} The number of points removed
|
||||
*/
|
||||
function polygonRemoveCollinearPoints(polygon, precision){
|
||||
var num = 0;
|
||||
for(var i=polygon.length-1; polygon.length>3 && i>=0; --i){
|
||||
if(collinear(polygonAt(polygon, i-1),polygonAt(polygon, i),polygonAt(polygon, i+1),precision)){
|
||||
// Remove the middle point
|
||||
polygon.splice(i%polygon.length,1);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove duplicate points in the polygon.
|
||||
* @method removeDuplicatePoints
|
||||
* @param {Number} [precision] The threshold to use when determining whether two points are the same. Use zero for best precision.
|
||||
*/
|
||||
function polygonRemoveDuplicatePoints(polygon, precision){
|
||||
for(var i=polygon.length-1; i>=1; --i){
|
||||
var pi = polygon[i];
|
||||
for(var j=i-1; j>=0; --j){
|
||||
if(points_eq(pi, polygon[j], precision)){
|
||||
polygon.splice(i,1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two scalars are equal
|
||||
* @static
|
||||
* @method eq
|
||||
* @param {Number} a
|
||||
* @param {Number} b
|
||||
* @param {Number} [precision]
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function scalar_eq(a,b,precision){
|
||||
precision = precision || 0;
|
||||
return Math.abs(a-b) <= precision;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if two points are equal
|
||||
* @static
|
||||
* @method points_eq
|
||||
* @param {Array} a
|
||||
* @param {Array} b
|
||||
* @param {Number} [precision]
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function points_eq(a,b,precision){
|
||||
return scalar_eq(a[0],b[0],precision) && scalar_eq(a[1],b[1],precision);
|
||||
}
|
||||
|
||||
},{}]},{},[1])
|
||||
(1)
|
||||
});
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,275 +0,0 @@
|
|||
/*!
|
||||
* matter-wrap 0.2.0 by Liam Brummitt 2017-07-04
|
||||
* https://github.com/liabru/matter-wrap
|
||||
* License MIT
|
||||
*/
|
||||
(function webpackUniversalModuleDefinition(root, factory) {
|
||||
if(typeof exports === 'object' && typeof module === 'object')
|
||||
module.exports = factory(require("matter-js"));
|
||||
else if(typeof define === 'function' && define.amd)
|
||||
define(["matter-js"], factory);
|
||||
else if(typeof exports === 'object')
|
||||
exports["MatterWrap"] = factory(require("matter-js"));
|
||||
else
|
||||
root["MatterWrap"] = factory(root["Matter"]);
|
||||
})(this, function(__WEBPACK_EXTERNAL_MODULE_0__) {
|
||||
return /******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId])
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
|
||||
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
|
||||
/******/ // identity function for calling harmony imports with the correct context
|
||||
/******/ __webpack_require__.i = function(value) { return value; };
|
||||
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, {
|
||||
/******/ configurable: false,
|
||||
/******/ enumerable: true,
|
||||
/******/ get: getter
|
||||
/******/ });
|
||||
/******/ }
|
||||
/******/ };
|
||||
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "/libs";
|
||||
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 1);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
module.exports = __WEBPACK_EXTERNAL_MODULE_0__;
|
||||
|
||||
/***/ }),
|
||||
/* 1 */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
|
||||
|
||||
var Matter = __webpack_require__(0);
|
||||
|
||||
/**
|
||||
* A coordinate wrapping plugin for matter.js.
|
||||
* See the readme for usage and examples.
|
||||
* @module MatterWrap
|
||||
*/
|
||||
var MatterWrap = {
|
||||
// plugin meta
|
||||
name: 'matter-wrap', // PLUGIN_NAME
|
||||
version: '0.1.3', // PLUGIN_VERSION
|
||||
for: 'matter-js@^0.12.0',
|
||||
|
||||
// installs the plugin where `base` is `Matter`
|
||||
// you should not need to call this directly.
|
||||
install: function install(base) {
|
||||
base.after('Engine.update', function () {
|
||||
MatterWrap.Engine.update(this);
|
||||
});
|
||||
},
|
||||
|
||||
Engine: {
|
||||
/**
|
||||
* Updates the engine by wrapping bodies and composites inside `engine.world`.
|
||||
* This is called automatically by the plugin.
|
||||
* @function MatterWrap.Engine.update
|
||||
* @param {Matter.Engine} engine The engine to update.
|
||||
* @returns {void} No return value.
|
||||
*/
|
||||
update: function update(engine) {
|
||||
var world = engine.world,
|
||||
bodies = Matter.Composite.allBodies(world),
|
||||
composites = Matter.Composite.allComposites(world);
|
||||
|
||||
for (var i = 0; i < bodies.length; i += 1) {
|
||||
var body = bodies[i];
|
||||
|
||||
if (body.plugin.wrap) {
|
||||
MatterWrap.Body.wrap(body, body.plugin.wrap);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < composites.length; i += 1) {
|
||||
var composite = composites[i];
|
||||
|
||||
if (composite.plugin.wrap) {
|
||||
MatterWrap.Composite.wrap(composite, composite.plugin.wrap);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Bounds: {
|
||||
/**
|
||||
* Returns a translation vector that wraps the `objectBounds` inside the `bounds`.
|
||||
* @function MatterWrap.Bounds.wrap
|
||||
* @param {Matter.Bounds} objectBounds The bounds of the object to wrap inside the bounds.
|
||||
* @param {Matter.Bounds} bounds The bounds to wrap the body inside.
|
||||
* @returns {?Matter.Vector} A translation vector (only if wrapping is required).
|
||||
*/
|
||||
wrap: function wrap(objectBounds, bounds) {
|
||||
var x = null,
|
||||
y = null;
|
||||
|
||||
if (typeof bounds.min.x !== 'undefined' && typeof bounds.max.x !== 'undefined') {
|
||||
if (objectBounds.min.x > bounds.max.x) {
|
||||
x = bounds.min.x - objectBounds.max.x;
|
||||
} else if (objectBounds.max.x < bounds.min.x) {
|
||||
x = bounds.max.x - objectBounds.min.x;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof bounds.min.y !== 'undefined' && typeof bounds.max.y !== 'undefined') {
|
||||
if (objectBounds.min.y > bounds.max.y) {
|
||||
y = bounds.min.y - objectBounds.max.y;
|
||||
} else if (objectBounds.max.y < bounds.min.y) {
|
||||
y = bounds.max.y - objectBounds.min.y;
|
||||
}
|
||||
}
|
||||
|
||||
if (x !== null || y !== null) {
|
||||
return {
|
||||
x: x || 0,
|
||||
y: y || 0
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Body: {
|
||||
/**
|
||||
* Wraps the `body` position such that it always stays within the given bounds.
|
||||
* Upon crossing a boundary the body will appear on the opposite side of the bounds,
|
||||
* while maintaining its velocity.
|
||||
* This is called automatically by the plugin.
|
||||
* @function MatterWrap.Body.wrap
|
||||
* @param {Matter.Body} body The body to wrap.
|
||||
* @param {Matter.Bounds} bounds The bounds to wrap the body inside.
|
||||
* @returns {?Matter.Vector} The translation vector that was applied (only if wrapping was required).
|
||||
*/
|
||||
wrap: function wrap(body, bounds) {
|
||||
var translation = MatterWrap.Bounds.wrap(body.bounds, bounds);
|
||||
|
||||
if (translation) {
|
||||
Matter.Body.translate(body, translation);
|
||||
}
|
||||
|
||||
return translation;
|
||||
}
|
||||
},
|
||||
|
||||
Composite: {
|
||||
/**
|
||||
* Returns the union of the bounds of all of the composite's bodies
|
||||
* (not accounting for constraints).
|
||||
* @function MatterWrap.Composite.bounds
|
||||
* @param {Matter.Composite} composite The composite.
|
||||
* @returns {Matter.Bounds} The composite bounds.
|
||||
*/
|
||||
bounds: function bounds(composite) {
|
||||
var bodies = Matter.Composite.allBodies(composite),
|
||||
vertices = [];
|
||||
|
||||
for (var i = 0; i < bodies.length; i += 1) {
|
||||
var body = bodies[i];
|
||||
vertices.push(body.bounds.min, body.bounds.max);
|
||||
}
|
||||
|
||||
return Matter.Bounds.create(vertices);
|
||||
},
|
||||
|
||||
/**
|
||||
* Wraps the `composite` position such that it always stays within the given bounds.
|
||||
* Upon crossing a boundary the composite will appear on the opposite side of the bounds,
|
||||
* while maintaining its velocity.
|
||||
* This is called automatically by the plugin.
|
||||
* @function MatterWrap.Composite.wrap
|
||||
* @param {Matter.Composite} composite The composite to wrap.
|
||||
* @param {Matter.Bounds} bounds The bounds to wrap the composite inside.
|
||||
* @returns {?Matter.Vector} The translation vector that was applied (only if wrapping was required).
|
||||
*/
|
||||
wrap: function wrap(composite, bounds) {
|
||||
var translation = MatterWrap.Bounds.wrap(MatterWrap.Composite.bounds(composite), bounds);
|
||||
|
||||
if (translation) {
|
||||
Matter.Composite.translate(composite, translation);
|
||||
}
|
||||
|
||||
return translation;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Matter.Plugin.register(MatterWrap);
|
||||
|
||||
module.exports = MatterWrap;
|
||||
|
||||
/**
|
||||
* @namespace Matter.Body
|
||||
* @see http://brm.io/matter-js/docs/classes/Body.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* This plugin adds a new property `body.plugin.wrap` to instances of `Matter.Body`.
|
||||
* This is a `Matter.Bounds` instance that specifies the wrapping region.
|
||||
* @property {Matter.Bounds} body.plugin.wrap
|
||||
* @memberof Matter.Body
|
||||
*/
|
||||
|
||||
/**
|
||||
* This plugin adds a new property `composite.plugin.wrap` to instances of `Matter.Composite`.
|
||||
* This is a `Matter.Bounds` instance that specifies the wrapping region.
|
||||
* @property {Matter.Bounds} composite.plugin.wrap
|
||||
* @memberof Matter.Composite
|
||||
*/
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
});
|
|
@ -1,849 +0,0 @@
|
|||
// SVGPathSeg API polyfill
|
||||
// https://github.com/progers/pathseg
|
||||
//
|
||||
// This is a drop-in replacement for the SVGPathSeg and SVGPathSegList APIs that were removed from
|
||||
// SVG2 (https://lists.w3.org/Archives/Public/www-svg/2015Jun/0044.html), including the latest spec
|
||||
// changes which were implemented in Firefox 43 and Chrome 46.
|
||||
|
||||
(function() { "use strict";
|
||||
if (!("SVGPathSeg" in window)) {
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSeg
|
||||
window.SVGPathSeg = function(type, typeAsLetter, owningPathSegList) {
|
||||
this.pathSegType = type;
|
||||
this.pathSegTypeAsLetter = typeAsLetter;
|
||||
this._owningPathSegList = owningPathSegList;
|
||||
}
|
||||
|
||||
window.SVGPathSeg.prototype.classname = "SVGPathSeg";
|
||||
|
||||
window.SVGPathSeg.PATHSEG_UNKNOWN = 0;
|
||||
window.SVGPathSeg.PATHSEG_CLOSEPATH = 1;
|
||||
window.SVGPathSeg.PATHSEG_MOVETO_ABS = 2;
|
||||
window.SVGPathSeg.PATHSEG_MOVETO_REL = 3;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_ABS = 4;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_REL = 5;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS = 6;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL = 7;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS = 8;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL = 9;
|
||||
window.SVGPathSeg.PATHSEG_ARC_ABS = 10;
|
||||
window.SVGPathSeg.PATHSEG_ARC_REL = 11;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS = 12;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL = 13;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS = 14;
|
||||
window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL = 15;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
|
||||
window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
|
||||
|
||||
// Notify owning PathSegList on any changes so they can be synchronized back to the path element.
|
||||
window.SVGPathSeg.prototype._segmentChanged = function() {
|
||||
if (this._owningPathSegList)
|
||||
this._owningPathSegList.segmentChanged(this);
|
||||
}
|
||||
|
||||
window.SVGPathSegClosePath = function(owningPathSegList) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CLOSEPATH, "z", owningPathSegList);
|
||||
}
|
||||
window.SVGPathSegClosePath.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegClosePath.prototype.toString = function() { return "[object SVGPathSegClosePath]"; }
|
||||
window.SVGPathSegClosePath.prototype._asPathString = function() { return this.pathSegTypeAsLetter; }
|
||||
window.SVGPathSegClosePath.prototype.clone = function() { return new window.SVGPathSegClosePath(undefined); }
|
||||
|
||||
window.SVGPathSegMovetoAbs = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_ABS, "M", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegMovetoAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegMovetoAbs.prototype.toString = function() { return "[object SVGPathSegMovetoAbs]"; }
|
||||
window.SVGPathSegMovetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegMovetoAbs.prototype.clone = function() { return new window.SVGPathSegMovetoAbs(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegMovetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegMovetoRel = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_MOVETO_REL, "m", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegMovetoRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegMovetoRel.prototype.toString = function() { return "[object SVGPathSegMovetoRel]"; }
|
||||
window.SVGPathSegMovetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegMovetoRel.prototype.clone = function() { return new window.SVGPathSegMovetoRel(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegMovetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoAbs = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_ABS, "L", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegLinetoAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoAbs.prototype.toString = function() { return "[object SVGPathSegLinetoAbs]"; }
|
||||
window.SVGPathSegLinetoAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegLinetoAbs.prototype.clone = function() { return new window.SVGPathSegLinetoAbs(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegLinetoAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoRel = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_REL, "l", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegLinetoRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoRel.prototype.toString = function() { return "[object SVGPathSegLinetoRel]"; }
|
||||
window.SVGPathSegLinetoRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegLinetoRel.prototype.clone = function() { return new window.SVGPathSegLinetoRel(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegLinetoRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoCubicAbs = function(owningPathSegList, x, y, x1, y1, x2, y2) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS, "C", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
window.SVGPathSegCurvetoCubicAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoCubicAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicAbs]"; }
|
||||
window.SVGPathSegCurvetoCubicAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoCubicAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicAbs(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoCubicRel = function(owningPathSegList, x, y, x1, y1, x2, y2) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL, "c", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
window.SVGPathSegCurvetoCubicRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoCubicRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicRel]"; }
|
||||
window.SVGPathSegCurvetoCubicRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoCubicRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicRel(undefined, this._x, this._y, this._x1, this._y1, this._x2, this._y2); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoQuadraticAbs = function(owningPathSegList, x, y, x1, y1) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS, "Q", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
}
|
||||
window.SVGPathSegCurvetoQuadraticAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoQuadraticAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticAbs]"; }
|
||||
window.SVGPathSegCurvetoQuadraticAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoQuadraticAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, this._x, this._y, this._x1, this._y1); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticAbs.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoQuadraticRel = function(owningPathSegList, x, y, x1, y1) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL, "q", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x1 = x1;
|
||||
this._y1 = y1;
|
||||
}
|
||||
window.SVGPathSegCurvetoQuadraticRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoQuadraticRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticRel]"; }
|
||||
window.SVGPathSegCurvetoQuadraticRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x1 + " " + this._y1 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoQuadraticRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticRel(undefined, this._x, this._y, this._x1, this._y1); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "x1", { get: function() { return this._x1; }, set: function(x1) { this._x1 = x1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticRel.prototype, "y1", { get: function() { return this._y1; }, set: function(y1) { this._y1 = y1; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegArcAbs = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_ABS, "A", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._r1 = r1;
|
||||
this._r2 = r2;
|
||||
this._angle = angle;
|
||||
this._largeArcFlag = largeArcFlag;
|
||||
this._sweepFlag = sweepFlag;
|
||||
}
|
||||
window.SVGPathSegArcAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegArcAbs.prototype.toString = function() { return "[object SVGPathSegArcAbs]"; }
|
||||
window.SVGPathSegArcAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegArcAbs.prototype.clone = function() { return new window.SVGPathSegArcAbs(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcAbs.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegArcRel = function(owningPathSegList, x, y, r1, r2, angle, largeArcFlag, sweepFlag) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_ARC_REL, "a", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._r1 = r1;
|
||||
this._r2 = r2;
|
||||
this._angle = angle;
|
||||
this._largeArcFlag = largeArcFlag;
|
||||
this._sweepFlag = sweepFlag;
|
||||
}
|
||||
window.SVGPathSegArcRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegArcRel.prototype.toString = function() { return "[object SVGPathSegArcRel]"; }
|
||||
window.SVGPathSegArcRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._r1 + " " + this._r2 + " " + this._angle + " " + (this._largeArcFlag ? "1" : "0") + " " + (this._sweepFlag ? "1" : "0") + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegArcRel.prototype.clone = function() { return new window.SVGPathSegArcRel(undefined, this._x, this._y, this._r1, this._r2, this._angle, this._largeArcFlag, this._sweepFlag); }
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "r1", { get: function() { return this._r1; }, set: function(r1) { this._r1 = r1; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "r2", { get: function() { return this._r2; }, set: function(r2) { this._r2 = r2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "angle", { get: function() { return this._angle; }, set: function(angle) { this._angle = angle; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "largeArcFlag", { get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { this._largeArcFlag = largeArcFlag; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegArcRel.prototype, "sweepFlag", { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { this._sweepFlag = sweepFlag; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoHorizontalAbs = function(owningPathSegList, x) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS, "H", owningPathSegList);
|
||||
this._x = x;
|
||||
}
|
||||
window.SVGPathSegLinetoHorizontalAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoHorizontalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalAbs]"; }
|
||||
window.SVGPathSegLinetoHorizontalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; }
|
||||
window.SVGPathSegLinetoHorizontalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalAbs(undefined, this._x); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoHorizontalAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoHorizontalRel = function(owningPathSegList, x) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL, "h", owningPathSegList);
|
||||
this._x = x;
|
||||
}
|
||||
window.SVGPathSegLinetoHorizontalRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoHorizontalRel.prototype.toString = function() { return "[object SVGPathSegLinetoHorizontalRel]"; }
|
||||
window.SVGPathSegLinetoHorizontalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x; }
|
||||
window.SVGPathSegLinetoHorizontalRel.prototype.clone = function() { return new window.SVGPathSegLinetoHorizontalRel(undefined, this._x); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoHorizontalRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoVerticalAbs = function(owningPathSegList, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS, "V", owningPathSegList);
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegLinetoVerticalAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoVerticalAbs.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalAbs]"; }
|
||||
window.SVGPathSegLinetoVerticalAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; }
|
||||
window.SVGPathSegLinetoVerticalAbs.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalAbs(undefined, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoVerticalAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegLinetoVerticalRel = function(owningPathSegList, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL, "v", owningPathSegList);
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegLinetoVerticalRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegLinetoVerticalRel.prototype.toString = function() { return "[object SVGPathSegLinetoVerticalRel]"; }
|
||||
window.SVGPathSegLinetoVerticalRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._y; }
|
||||
window.SVGPathSegLinetoVerticalRel.prototype.clone = function() { return new window.SVGPathSegLinetoVerticalRel(undefined, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegLinetoVerticalRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs = function(owningPathSegList, x, y, x2, y2) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS, "S", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothAbs]"; }
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoCubicSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, this._x, this._y, this._x2, this._y2); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothAbs.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoCubicSmoothRel = function(owningPathSegList, x, y, x2, y2) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL, "s", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._x2 = x2;
|
||||
this._y2 = y2;
|
||||
}
|
||||
window.SVGPathSegCurvetoCubicSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoCubicSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoCubicSmoothRel]"; }
|
||||
window.SVGPathSegCurvetoCubicSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x2 + " " + this._y2 + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoCubicSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, this._x, this._y, this._x2, this._y2); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "x2", { get: function() { return this._x2; }, set: function(x2) { this._x2 = x2; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoCubicSmoothRel.prototype, "y2", { get: function() { return this._y2; }, set: function(y2) { this._y2 = y2; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS, "T", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothAbs]"; }
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothAbs.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel = function(owningPathSegList, x, y) {
|
||||
window.SVGPathSeg.call(this, window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL, "t", owningPathSegList);
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
}
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype = Object.create(window.SVGPathSeg.prototype);
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.toString = function() { return "[object SVGPathSegCurvetoQuadraticSmoothRel]"; }
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype._asPathString = function() { return this.pathSegTypeAsLetter + " " + this._x + " " + this._y; }
|
||||
window.SVGPathSegCurvetoQuadraticSmoothRel.prototype.clone = function() { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, this._x, this._y); }
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "x", { get: function() { return this._x; }, set: function(x) { this._x = x; this._segmentChanged(); }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathSegCurvetoQuadraticSmoothRel.prototype, "y", { get: function() { return this._y; }, set: function(y) { this._y = y; this._segmentChanged(); }, enumerable: true });
|
||||
|
||||
// Add createSVGPathSeg* functions to window.SVGPathElement.
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-Interfacewindow.SVGPathElement.
|
||||
window.SVGPathElement.prototype.createSVGPathSegClosePath = function() { return new window.SVGPathSegClosePath(undefined); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegMovetoAbs = function(x, y) { return new window.SVGPathSegMovetoAbs(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegMovetoRel = function(x, y) { return new window.SVGPathSegMovetoRel(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoAbs = function(x, y) { return new window.SVGPathSegLinetoAbs(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoRel = function(x, y) { return new window.SVGPathSegLinetoRel(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicAbs = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicAbs(undefined, x, y, x1, y1, x2, y2); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicRel = function(x, y, x1, y1, x2, y2) { return new window.SVGPathSegCurvetoCubicRel(undefined, x, y, x1, y1, x2, y2); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticAbs = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticAbs(undefined, x, y, x1, y1); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticRel = function(x, y, x1, y1) { return new window.SVGPathSegCurvetoQuadraticRel(undefined, x, y, x1, y1); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegArcAbs = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcAbs(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegArcRel = function(x, y, r1, r2, angle, largeArcFlag, sweepFlag) { return new window.SVGPathSegArcRel(undefined, x, y, r1, r2, angle, largeArcFlag, sweepFlag); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalAbs = function(x) { return new window.SVGPathSegLinetoHorizontalAbs(undefined, x); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoHorizontalRel = function(x) { return new window.SVGPathSegLinetoHorizontalRel(undefined, x); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalAbs = function(y) { return new window.SVGPathSegLinetoVerticalAbs(undefined, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegLinetoVerticalRel = function(y) { return new window.SVGPathSegLinetoVerticalRel(undefined, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothAbs = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothAbs(undefined, x, y, x2, y2); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoCubicSmoothRel = function(x, y, x2, y2) { return new window.SVGPathSegCurvetoCubicSmoothRel(undefined, x, y, x2, y2); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothAbs = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothAbs(undefined, x, y); }
|
||||
window.SVGPathElement.prototype.createSVGPathSegCurvetoQuadraticSmoothRel = function(x, y) { return new window.SVGPathSegCurvetoQuadraticSmoothRel(undefined, x, y); }
|
||||
|
||||
if (!("getPathSegAtLength" in window.SVGPathElement.prototype)) {
|
||||
// Add getPathSegAtLength to SVGPathElement.
|
||||
// Spec: https://www.w3.org/TR/SVG11/single-page.html#paths-__svg__SVGPathElement__getPathSegAtLength
|
||||
// This polyfill requires SVGPathElement.getTotalLength to implement the distance-along-a-path algorithm.
|
||||
window.SVGPathElement.prototype.getPathSegAtLength = function(distance) {
|
||||
if (distance === undefined || !isFinite(distance))
|
||||
throw "Invalid arguments.";
|
||||
|
||||
var measurementElement = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||||
measurementElement.setAttribute("d", this.getAttribute("d"));
|
||||
var lastPathSegment = measurementElement.pathSegList.numberOfItems - 1;
|
||||
|
||||
// If the path is empty, return 0.
|
||||
if (lastPathSegment <= 0)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
measurementElement.pathSegList.removeItem(lastPathSegment);
|
||||
if (distance > measurementElement.getTotalLength())
|
||||
break;
|
||||
lastPathSegment--;
|
||||
} while (lastPathSegment > 0);
|
||||
return lastPathSegment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checking for SVGPathSegList in window checks for the case of an implementation without the
|
||||
// SVGPathSegList API.
|
||||
// The second check for appendItem is specific to Firefox 59+ which removed only parts of the
|
||||
// SVGPathSegList API (e.g., appendItem). In this case we need to re-implement the entire API
|
||||
// so the polyfill data (i.e., _list) is used throughout.
|
||||
if (!("SVGPathSegList" in window) || !("appendItem" in window.SVGPathSegList.prototype)) {
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGPathSegList
|
||||
window.SVGPathSegList = function(pathElement) {
|
||||
this._pathElement = pathElement;
|
||||
this._list = this._parsePath(this._pathElement.getAttribute("d"));
|
||||
|
||||
// Use a MutationObserver to catch changes to the path's "d" attribute.
|
||||
this._mutationObserverConfig = { "attributes": true, "attributeFilter": ["d"] };
|
||||
this._pathElementMutationObserver = new MutationObserver(this._updateListFromPathMutations.bind(this));
|
||||
this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.classname = "SVGPathSegList";
|
||||
|
||||
Object.defineProperty(window.SVGPathSegList.prototype, "numberOfItems", {
|
||||
get: function() {
|
||||
this._checkPathSynchronizedToList();
|
||||
return this._list.length;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
// Add the pathSegList accessors to window.SVGPathElement.
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-InterfaceSVGAnimatedPathData
|
||||
Object.defineProperty(window.SVGPathElement.prototype, "pathSegList", {
|
||||
get: function() {
|
||||
if (!this._pathSegList)
|
||||
this._pathSegList = new window.SVGPathSegList(this);
|
||||
return this._pathSegList;
|
||||
},
|
||||
enumerable: true
|
||||
});
|
||||
// FIXME: The following are not implemented and simply return window.SVGPathElement.pathSegList.
|
||||
Object.defineProperty(window.SVGPathElement.prototype, "normalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathElement.prototype, "animatedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
|
||||
Object.defineProperty(window.SVGPathElement.prototype, "animatedNormalizedPathSegList", { get: function() { return this.pathSegList; }, enumerable: true });
|
||||
|
||||
// Process any pending mutations to the path element and update the list as needed.
|
||||
// This should be the first call of all public functions and is needed because
|
||||
// MutationObservers are not synchronous so we can have pending asynchronous mutations.
|
||||
window.SVGPathSegList.prototype._checkPathSynchronizedToList = function() {
|
||||
this._updateListFromPathMutations(this._pathElementMutationObserver.takeRecords());
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype._updateListFromPathMutations = function(mutationRecords) {
|
||||
if (!this._pathElement)
|
||||
return;
|
||||
var hasPathMutations = false;
|
||||
mutationRecords.forEach(function(record) {
|
||||
if (record.attributeName == "d")
|
||||
hasPathMutations = true;
|
||||
});
|
||||
if (hasPathMutations)
|
||||
this._list = this._parsePath(this._pathElement.getAttribute("d"));
|
||||
}
|
||||
|
||||
// Serialize the list and update the path's 'd' attribute.
|
||||
window.SVGPathSegList.prototype._writeListToPath = function() {
|
||||
this._pathElementMutationObserver.disconnect();
|
||||
this._pathElement.setAttribute("d", window.SVGPathSegList._pathSegArrayAsString(this._list));
|
||||
this._pathElementMutationObserver.observe(this._pathElement, this._mutationObserverConfig);
|
||||
}
|
||||
|
||||
// When a path segment changes the list needs to be synchronized back to the path element.
|
||||
window.SVGPathSegList.prototype.segmentChanged = function(pathSeg) {
|
||||
this._writeListToPath();
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.clear = function() {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._list.forEach(function(pathSeg) {
|
||||
pathSeg._owningPathSegList = null;
|
||||
});
|
||||
this._list = [];
|
||||
this._writeListToPath();
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.initialize = function(newItem) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._list = [newItem];
|
||||
newItem._owningPathSegList = this;
|
||||
this._writeListToPath();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype._checkValidIndex = function(index) {
|
||||
if (isNaN(index) || index < 0 || index >= this.numberOfItems)
|
||||
throw "INDEX_SIZE_ERR";
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.getItem = function(index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._checkValidIndex(index);
|
||||
return this._list[index];
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.insertItemBefore = function(newItem, index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
// Spec: If the index is greater than or equal to numberOfItems, then the new item is appended to the end of the list.
|
||||
if (index > this.numberOfItems)
|
||||
index = this.numberOfItems;
|
||||
if (newItem._owningPathSegList) {
|
||||
// SVG2 spec says to make a copy.
|
||||
newItem = newItem.clone();
|
||||
}
|
||||
this._list.splice(index, 0, newItem);
|
||||
newItem._owningPathSegList = this;
|
||||
this._writeListToPath();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.replaceItem = function(newItem, index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
if (newItem._owningPathSegList) {
|
||||
// SVG2 spec says to make a copy.
|
||||
newItem = newItem.clone();
|
||||
}
|
||||
this._checkValidIndex(index);
|
||||
this._list[index] = newItem;
|
||||
newItem._owningPathSegList = this;
|
||||
this._writeListToPath();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.removeItem = function(index) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
this._checkValidIndex(index);
|
||||
var item = this._list[index];
|
||||
this._list.splice(index, 1);
|
||||
this._writeListToPath();
|
||||
return item;
|
||||
}
|
||||
|
||||
window.SVGPathSegList.prototype.appendItem = function(newItem) {
|
||||
this._checkPathSynchronizedToList();
|
||||
|
||||
if (newItem._owningPathSegList) {
|
||||
// SVG2 spec says to make a copy.
|
||||
newItem = newItem.clone();
|
||||
}
|
||||
this._list.push(newItem);
|
||||
newItem._owningPathSegList = this;
|
||||
// TODO: Optimize this to just append to the existing attribute.
|
||||
this._writeListToPath();
|
||||
return newItem;
|
||||
}
|
||||
|
||||
window.SVGPathSegList._pathSegArrayAsString = function(pathSegArray) {
|
||||
var string = "";
|
||||
var first = true;
|
||||
pathSegArray.forEach(function(pathSeg) {
|
||||
if (first) {
|
||||
first = false;
|
||||
string += pathSeg._asPathString();
|
||||
} else {
|
||||
string += " " + pathSeg._asPathString();
|
||||
}
|
||||
});
|
||||
return string;
|
||||
}
|
||||
|
||||
// This closely follows SVGPathParser::parsePath from Source/core/svg/SVGPathParser.cpp.
|
||||
window.SVGPathSegList.prototype._parsePath = function(string) {
|
||||
if (!string || string.length == 0)
|
||||
return [];
|
||||
|
||||
var owningPathSegList = this;
|
||||
|
||||
var Builder = function() {
|
||||
this.pathSegList = [];
|
||||
}
|
||||
|
||||
Builder.prototype.appendSegment = function(pathSeg) {
|
||||
this.pathSegList.push(pathSeg);
|
||||
}
|
||||
|
||||
var Source = function(string) {
|
||||
this._string = string;
|
||||
this._currentIndex = 0;
|
||||
this._endIndex = this._string.length;
|
||||
this._previousCommand = window.SVGPathSeg.PATHSEG_UNKNOWN;
|
||||
|
||||
this._skipOptionalSpaces();
|
||||
}
|
||||
|
||||
Source.prototype._isCurrentSpace = function() {
|
||||
var character = this._string[this._currentIndex];
|
||||
return character <= " " && (character == " " || character == "\n" || character == "\t" || character == "\r" || character == "\f");
|
||||
}
|
||||
|
||||
Source.prototype._skipOptionalSpaces = function() {
|
||||
while (this._currentIndex < this._endIndex && this._isCurrentSpace())
|
||||
this._currentIndex++;
|
||||
return this._currentIndex < this._endIndex;
|
||||
}
|
||||
|
||||
Source.prototype._skipOptionalSpacesOrDelimiter = function() {
|
||||
if (this._currentIndex < this._endIndex && !this._isCurrentSpace() && this._string.charAt(this._currentIndex) != ",")
|
||||
return false;
|
||||
if (this._skipOptionalSpaces()) {
|
||||
if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ",") {
|
||||
this._currentIndex++;
|
||||
this._skipOptionalSpaces();
|
||||
}
|
||||
}
|
||||
return this._currentIndex < this._endIndex;
|
||||
}
|
||||
|
||||
Source.prototype.hasMoreData = function() {
|
||||
return this._currentIndex < this._endIndex;
|
||||
}
|
||||
|
||||
Source.prototype.peekSegmentType = function() {
|
||||
var lookahead = this._string[this._currentIndex];
|
||||
return this._pathSegTypeFromChar(lookahead);
|
||||
}
|
||||
|
||||
Source.prototype._pathSegTypeFromChar = function(lookahead) {
|
||||
switch (lookahead) {
|
||||
case "Z":
|
||||
case "z":
|
||||
return window.SVGPathSeg.PATHSEG_CLOSEPATH;
|
||||
case "M":
|
||||
return window.SVGPathSeg.PATHSEG_MOVETO_ABS;
|
||||
case "m":
|
||||
return window.SVGPathSeg.PATHSEG_MOVETO_REL;
|
||||
case "L":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_ABS;
|
||||
case "l":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_REL;
|
||||
case "C":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS;
|
||||
case "c":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL;
|
||||
case "Q":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS;
|
||||
case "q":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL;
|
||||
case "A":
|
||||
return window.SVGPathSeg.PATHSEG_ARC_ABS;
|
||||
case "a":
|
||||
return window.SVGPathSeg.PATHSEG_ARC_REL;
|
||||
case "H":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS;
|
||||
case "h":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL;
|
||||
case "V":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS;
|
||||
case "v":
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL;
|
||||
case "S":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS;
|
||||
case "s":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL;
|
||||
case "T":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS;
|
||||
case "t":
|
||||
return window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL;
|
||||
default:
|
||||
return window.SVGPathSeg.PATHSEG_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
Source.prototype._nextCommandHelper = function(lookahead, previousCommand) {
|
||||
// Check for remaining coordinates in the current command.
|
||||
if ((lookahead == "+" || lookahead == "-" || lookahead == "." || (lookahead >= "0" && lookahead <= "9")) && previousCommand != window.SVGPathSeg.PATHSEG_CLOSEPATH) {
|
||||
if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_ABS)
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_ABS;
|
||||
if (previousCommand == window.SVGPathSeg.PATHSEG_MOVETO_REL)
|
||||
return window.SVGPathSeg.PATHSEG_LINETO_REL;
|
||||
return previousCommand;
|
||||
}
|
||||
return window.SVGPathSeg.PATHSEG_UNKNOWN;
|
||||
}
|
||||
|
||||
Source.prototype.initialCommandIsMoveTo = function() {
|
||||
// If the path is empty it is still valid, so return true.
|
||||
if (!this.hasMoreData())
|
||||
return true;
|
||||
var command = this.peekSegmentType();
|
||||
// Path must start with moveTo.
|
||||
return command == window.SVGPathSeg.PATHSEG_MOVETO_ABS || command == window.SVGPathSeg.PATHSEG_MOVETO_REL;
|
||||
}
|
||||
|
||||
// Parse a number from an SVG path. This very closely follows genericParseNumber(...) from Source/core/svg/SVGParserUtilities.cpp.
|
||||
// Spec: http://www.w3.org/TR/SVG11/single-page.html#paths-PathDataBNF
|
||||
Source.prototype._parseNumber = function() {
|
||||
var exponent = 0;
|
||||
var integer = 0;
|
||||
var frac = 1;
|
||||
var decimal = 0;
|
||||
var sign = 1;
|
||||
var expsign = 1;
|
||||
|
||||
var startIndex = this._currentIndex;
|
||||
|
||||
this._skipOptionalSpaces();
|
||||
|
||||
// Read the sign.
|
||||
if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "+")
|
||||
this._currentIndex++;
|
||||
else if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == "-") {
|
||||
this._currentIndex++;
|
||||
sign = -1;
|
||||
}
|
||||
|
||||
if (this._currentIndex == this._endIndex || ((this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9") && this._string.charAt(this._currentIndex) != "."))
|
||||
// The first character of a number must be one of [0-9+-.].
|
||||
return undefined;
|
||||
|
||||
// Read the integer part, build right-to-left.
|
||||
var startIntPartIndex = this._currentIndex;
|
||||
while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9")
|
||||
this._currentIndex++; // Advance to first non-digit.
|
||||
|
||||
if (this._currentIndex != startIntPartIndex) {
|
||||
var scanIntPartIndex = this._currentIndex - 1;
|
||||
var multiplier = 1;
|
||||
while (scanIntPartIndex >= startIntPartIndex) {
|
||||
integer += multiplier * (this._string.charAt(scanIntPartIndex--) - "0");
|
||||
multiplier *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the decimals.
|
||||
if (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) == ".") {
|
||||
this._currentIndex++;
|
||||
|
||||
// There must be a least one digit following the .
|
||||
if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9")
|
||||
return undefined;
|
||||
while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
|
||||
frac *= 10;
|
||||
decimal += (this._string.charAt(this._currentIndex) - "0") / frac;
|
||||
this._currentIndex += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the exponent part.
|
||||
if (this._currentIndex != startIndex && this._currentIndex + 1 < this._endIndex && (this._string.charAt(this._currentIndex) == "e" || this._string.charAt(this._currentIndex) == "E") && (this._string.charAt(this._currentIndex + 1) != "x" && this._string.charAt(this._currentIndex + 1) != "m")) {
|
||||
this._currentIndex++;
|
||||
|
||||
// Read the sign of the exponent.
|
||||
if (this._string.charAt(this._currentIndex) == "+") {
|
||||
this._currentIndex++;
|
||||
} else if (this._string.charAt(this._currentIndex) == "-") {
|
||||
this._currentIndex++;
|
||||
expsign = -1;
|
||||
}
|
||||
|
||||
// There must be an exponent.
|
||||
if (this._currentIndex >= this._endIndex || this._string.charAt(this._currentIndex) < "0" || this._string.charAt(this._currentIndex) > "9")
|
||||
return undefined;
|
||||
|
||||
while (this._currentIndex < this._endIndex && this._string.charAt(this._currentIndex) >= "0" && this._string.charAt(this._currentIndex) <= "9") {
|
||||
exponent *= 10;
|
||||
exponent += (this._string.charAt(this._currentIndex) - "0");
|
||||
this._currentIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
var number = integer + decimal;
|
||||
number *= sign;
|
||||
|
||||
if (exponent)
|
||||
number *= Math.pow(10, expsign * exponent);
|
||||
|
||||
if (startIndex == this._currentIndex)
|
||||
return undefined;
|
||||
|
||||
this._skipOptionalSpacesOrDelimiter();
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
Source.prototype._parseArcFlag = function() {
|
||||
if (this._currentIndex >= this._endIndex)
|
||||
return undefined;
|
||||
var flag = false;
|
||||
var flagChar = this._string.charAt(this._currentIndex++);
|
||||
if (flagChar == "0")
|
||||
flag = false;
|
||||
else if (flagChar == "1")
|
||||
flag = true;
|
||||
else
|
||||
return undefined;
|
||||
|
||||
this._skipOptionalSpacesOrDelimiter();
|
||||
return flag;
|
||||
}
|
||||
|
||||
Source.prototype.parseSegment = function() {
|
||||
var lookahead = this._string[this._currentIndex];
|
||||
var command = this._pathSegTypeFromChar(lookahead);
|
||||
if (command == window.SVGPathSeg.PATHSEG_UNKNOWN) {
|
||||
// Possibly an implicit command. Not allowed if this is the first command.
|
||||
if (this._previousCommand == window.SVGPathSeg.PATHSEG_UNKNOWN)
|
||||
return null;
|
||||
command = this._nextCommandHelper(lookahead, this._previousCommand);
|
||||
if (command == window.SVGPathSeg.PATHSEG_UNKNOWN)
|
||||
return null;
|
||||
} else {
|
||||
this._currentIndex++;
|
||||
}
|
||||
|
||||
this._previousCommand = command;
|
||||
|
||||
switch (command) {
|
||||
case window.SVGPathSeg.PATHSEG_MOVETO_REL:
|
||||
return new window.SVGPathSegMovetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_MOVETO_ABS:
|
||||
return new window.SVGPathSegMovetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_REL:
|
||||
return new window.SVGPathSegLinetoRel(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_ABS:
|
||||
return new window.SVGPathSegLinetoAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_REL:
|
||||
return new window.SVGPathSegLinetoHorizontalRel(owningPathSegList, this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_HORIZONTAL_ABS:
|
||||
return new window.SVGPathSegLinetoHorizontalAbs(owningPathSegList, this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_REL:
|
||||
return new window.SVGPathSegLinetoVerticalRel(owningPathSegList, this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_LINETO_VERTICAL_ABS:
|
||||
return new window.SVGPathSegLinetoVerticalAbs(owningPathSegList, this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_CLOSEPATH:
|
||||
this._skipOptionalSpaces();
|
||||
return new window.SVGPathSegClosePath(owningPathSegList);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_REL:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoCubicRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_ABS:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoCubicAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.x2, points.y2);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_REL:
|
||||
var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoCubicSmoothRel(owningPathSegList, points.x, points.y, points.x2, points.y2);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_CUBIC_SMOOTH_ABS:
|
||||
var points = {x2: this._parseNumber(), y2: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoCubicSmoothAbs(owningPathSegList, points.x, points.y, points.x2, points.y2);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_REL:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoQuadraticRel(owningPathSegList, points.x, points.y, points.x1, points.y1);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_ABS:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegCurvetoQuadraticAbs(owningPathSegList, points.x, points.y, points.x1, points.y1);
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL:
|
||||
return new window.SVGPathSegCurvetoQuadraticSmoothRel(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS:
|
||||
return new window.SVGPathSegCurvetoQuadraticSmoothAbs(owningPathSegList, this._parseNumber(), this._parseNumber());
|
||||
case window.SVGPathSeg.PATHSEG_ARC_REL:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegArcRel(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
|
||||
case window.SVGPathSeg.PATHSEG_ARC_ABS:
|
||||
var points = {x1: this._parseNumber(), y1: this._parseNumber(), arcAngle: this._parseNumber(), arcLarge: this._parseArcFlag(), arcSweep: this._parseArcFlag(), x: this._parseNumber(), y: this._parseNumber()};
|
||||
return new window.SVGPathSegArcAbs(owningPathSegList, points.x, points.y, points.x1, points.y1, points.arcAngle, points.arcLarge, points.arcSweep);
|
||||
default:
|
||||
throw "Unknown path seg type."
|
||||
}
|
||||
}
|
||||
|
||||
var builder = new Builder();
|
||||
var source = new Source(string);
|
||||
|
||||
if (!source.initialCommandIsMoveTo())
|
||||
return [];
|
||||
while (source.hasMoreData()) {
|
||||
var pathSeg = source.parseSegment();
|
||||
if (!pathSeg)
|
||||
return [];
|
||||
builder.appendSegment(pathSeg);
|
||||
}
|
||||
|
||||
return builder.pathSegList;
|
||||
}
|
||||
}
|
||||
}());
|
171
demo/src/Compare.js
Normal file
171
demo/src/Compare.js
Normal file
|
@ -0,0 +1,171 @@
|
|||
/**
|
||||
* A Matter.js version comparison testbed based on MatterTools.
|
||||
*
|
||||
* Tool to interactively compare engine results of
|
||||
* development version against the previous release.
|
||||
*
|
||||
* USAGE: [host]?compare[=frames]#[example]
|
||||
* e.g. http://localhost:8000/?compare=120#mixed
|
||||
*
|
||||
* @module Compare
|
||||
*/
|
||||
|
||||
var MatterTools = require('matter-tools');
|
||||
var MatterDev = require('MatterDev');
|
||||
var MatterBuild = require('MatterBuild');
|
||||
|
||||
var compare = function(examples, isDev) {
|
||||
// create primary demo for dev build
|
||||
var demo = MatterTools.Demo.create({
|
||||
toolbar: {
|
||||
title: 'matter-js ・ ' + (isDev ? 'dev' : '') + ' ・ comparing to ' + MatterBuild.version,
|
||||
url: 'https://github.com/liabru/matter-js',
|
||||
reset: true,
|
||||
source: true,
|
||||
inspector: true,
|
||||
tools: true,
|
||||
fullscreen: true,
|
||||
exampleSelect: true
|
||||
},
|
||||
tools: {
|
||||
inspector: true,
|
||||
gui: true
|
||||
},
|
||||
inline: false,
|
||||
preventZoom: true,
|
||||
resetOnOrientation: true,
|
||||
routing: true,
|
||||
startExample: 'mixed',
|
||||
examples: examples
|
||||
});
|
||||
|
||||
// create secondary demo for release build
|
||||
var demoBuild = MatterTools.Demo.create({
|
||||
toolbar: {
|
||||
title: 'matter-js-compare-build',
|
||||
reset: false,
|
||||
source: false,
|
||||
inspector: false,
|
||||
tools: false,
|
||||
fullscreen: false,
|
||||
exampleSelect: false
|
||||
},
|
||||
tools: {
|
||||
inspector: false,
|
||||
gui: false
|
||||
},
|
||||
inline: false,
|
||||
preventZoom: true,
|
||||
resetOnOrientation: true,
|
||||
routing: false,
|
||||
startExample: 'mixed',
|
||||
examples: examples.map(function(example) {
|
||||
return Matter.Common.extend({}, example);
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* NOTE: For the actual example code, refer to the source files in `/examples/`.
|
||||
* The code below is tooling for Matter.js maintainers to compare versions of Matter.
|
||||
*/
|
||||
|
||||
// build version should not run itself
|
||||
MatterBuild.Runner.run = function() {};
|
||||
MatterBuild.Render.run = function() {};
|
||||
|
||||
// maintain original references to patched methods
|
||||
MatterDev.Runner._tick = MatterDev.Runner.tick;
|
||||
MatterDev.Render._world = MatterDev.Render.world;
|
||||
MatterBuild.Mouse._setElement = MatterBuild.Mouse.setElement;
|
||||
|
||||
// patch MatterTools to control both demo versions simultaneously
|
||||
MatterTools.Demo._setExample = MatterTools.Demo.setExample;
|
||||
MatterTools.Demo.setExample = function(_demo, example) {
|
||||
MatterBuild.Common._nextId = MatterBuild.Common._seed = 0;
|
||||
MatterDev.Common._nextId = MatterDev.Common._seed = 0;
|
||||
|
||||
MatterBuild.Plugin._registry = MatterDev.Plugin._registry;
|
||||
MatterBuild.use.apply(null, MatterDev.used);
|
||||
|
||||
window.Matter = MatterDev;
|
||||
MatterTools.Demo._setExample(
|
||||
demo, demo.examples.find(function(e) { return e.name === example.name; })
|
||||
);
|
||||
|
||||
var maxTicks = parseFloat(window.location.search.split('=')[1]);
|
||||
var ticks = 0;
|
||||
|
||||
MatterDev.Runner.tick = function(runner, engine, time) {
|
||||
if (ticks === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ticks >= maxTicks) {
|
||||
console.info(
|
||||
'Demo.Compare: ran ' + ticks + ' ticks, timestamp is now '
|
||||
+ engine.timing.timestamp.toFixed(2)
|
||||
);
|
||||
|
||||
ticks = -1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ticks += 1;
|
||||
|
||||
var demoBuildInstance = demoBuild.example.instance;
|
||||
runner.isFixed = demoBuildInstance.runner.isFixed = true;
|
||||
runner.delta = demoBuildInstance.runner.delta = 1000 / 60;
|
||||
|
||||
window.Matter = MatterBuild;
|
||||
MatterBuild.Runner.tick(demoBuildInstance.runner, demoBuildInstance.engine, time);
|
||||
window.Matter = MatterDev;
|
||||
return MatterDev.Runner._tick(runner, engine, time);
|
||||
};
|
||||
|
||||
MatterDev.Render.world = function(render) {
|
||||
window.Matter = MatterBuild;
|
||||
MatterBuild.Render.world(demoBuild.example.instance.render);
|
||||
window.Matter = MatterDev;
|
||||
return MatterDev.Render._world(render);
|
||||
};
|
||||
|
||||
MatterBuild.Mouse.setElement = function(mouse) {
|
||||
return MatterBuild.Mouse._setElement(mouse, demo.example.instance.render.canvas);
|
||||
};
|
||||
|
||||
window.Matter = MatterBuild;
|
||||
MatterTools.Demo._setExample(
|
||||
demoBuild, demoBuild.examples.find(function(e) { return e.name === example.name; })
|
||||
);
|
||||
|
||||
window.Matter = MatterDev;
|
||||
};
|
||||
|
||||
// reset both engine versions simultaneously
|
||||
MatterTools.Demo._reset = MatterTools.Demo.reset;
|
||||
MatterTools.Demo.reset = function(_demo) {
|
||||
MatterBuild.Common._nextId = MatterBuild.Common._seed = 0;
|
||||
MatterDev.Common._nextId = MatterDev.Common._seed = 0;
|
||||
|
||||
window.Matter = MatterBuild;
|
||||
MatterTools.Demo._reset(demoBuild);
|
||||
|
||||
window.Matter = MatterDev;
|
||||
MatterTools.Demo._reset(demo);
|
||||
};
|
||||
|
||||
document.body.appendChild(demo.dom.root);
|
||||
document.body.appendChild(demoBuild.dom.root);
|
||||
|
||||
MatterTools.Demo.start(demo);
|
||||
|
||||
document.title = 'Matter.js Compare' + (isDev ? ' ・ Dev' : '');
|
||||
|
||||
console.info(
|
||||
'Demo.Compare: matter-js@' + MatterDev.version +
|
||||
' with matter-js@' + MatterBuild.version
|
||||
);
|
||||
};
|
||||
|
||||
module.exports = { compare: compare };
|
61
demo/src/Demo.js
Normal file
61
demo/src/Demo.js
Normal file
|
@ -0,0 +1,61 @@
|
|||
/**
|
||||
* A Matter.js demo and development testbed based on MatterTools.
|
||||
*
|
||||
* For a simpler, minimal Matter.js example see:
|
||||
* https://github.com/liabru/matter-js/wiki/Getting-started
|
||||
*
|
||||
* The source for examples can be found at `/examples/`.
|
||||
*
|
||||
* @module Demo
|
||||
*/
|
||||
|
||||
var MatterTools = require('matter-tools');
|
||||
|
||||
var demo = function(examples, isDev) {
|
||||
var demo = MatterTools.Demo.create({
|
||||
toolbar: {
|
||||
title: 'matter-js' + (isDev ? ' ・ dev' : ''),
|
||||
url: 'https://github.com/liabru/matter-js',
|
||||
reset: true,
|
||||
source: true,
|
||||
inspector: true,
|
||||
tools: true,
|
||||
fullscreen: true,
|
||||
exampleSelect: true
|
||||
},
|
||||
tools: {
|
||||
inspector: true,
|
||||
gui: true
|
||||
},
|
||||
inline: false,
|
||||
preventZoom: true,
|
||||
resetOnOrientation: true,
|
||||
routing: true,
|
||||
startExample: 'mixed',
|
||||
examples: examples
|
||||
});
|
||||
|
||||
window.MatterDemoInstance = demo;
|
||||
|
||||
document.body.appendChild(demo.dom.root);
|
||||
document.title = 'Matter.js Demo' + (isDev ? ' ・ Dev' : '');
|
||||
|
||||
MatterTools.Demo.start(demo);
|
||||
|
||||
if (isDev) {
|
||||
var buttonSource = demo.dom.buttonSource;
|
||||
var buttonCompare = buttonSource.cloneNode(true);
|
||||
buttonCompare.textContent = '⎄';
|
||||
buttonCompare.title = 'Compare';
|
||||
buttonCompare.href = '?compare';
|
||||
buttonCompare.target = '';
|
||||
buttonCompare.className = 'matter-btn matter-btn-compare';
|
||||
buttonCompare.addEventListener('click', function(event) {
|
||||
window.location = '?compare#' + demo.example.id;
|
||||
event.preventDefault();
|
||||
});
|
||||
buttonSource.parentNode.insertBefore(buttonCompare, buttonSource.nextSibling);
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = { demo: demo };
|
55
demo/src/index.ejs
Normal file
55
demo/src/index.ejs
Normal file
|
@ -0,0 +1,55 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no,minimal-ui">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<meta name="msapplication-navbutton-color" content="#000000">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<meta name="robots" content="noindex">
|
||||
<title>Matter.js Demo</title>
|
||||
|
||||
<style type="text/css">
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.matter-btn-compare.matter-btn {
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.matter-js-compare-build.matter-demo {
|
||||
position: absolute;
|
||||
background: none;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.matter-js-compare-build.matter-demo .matter-header-outer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.matter-js-compare-build.matter-demo canvas {
|
||||
opacity: 0.5;
|
||||
background: transparent !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body><% for (var chunk in htmlWebpackPlugin.files.js) { %>
|
||||
<script src="<%= htmlWebpackPlugin.files.js[chunk] %>"></script><% } %>
|
||||
</body>
|
||||
</html>
|
40
demo/src/index.js
Normal file
40
demo/src/index.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* Initialise and start the browser demo / compare tool.
|
||||
*
|
||||
* For a simpler, minimal Matter.js example see:
|
||||
* https://github.com/liabru/matter-js/wiki/Getting-started
|
||||
*
|
||||
* The source for examples can be found at `/examples/`.
|
||||
*
|
||||
* @module Index
|
||||
*/
|
||||
|
||||
var Matter = require('matter-js');
|
||||
var Examples = require('../../examples/index');
|
||||
var compare = require('./Compare').compare;
|
||||
var demo = require('./Demo').demo;
|
||||
|
||||
// browser globals
|
||||
window.decomp = require('poly-decomp');
|
||||
window.pathseg = require('pathseg');
|
||||
window.MatterTools = require('matter-tools');
|
||||
window.Matter = Matter;
|
||||
|
||||
// prepare examples
|
||||
var examples = Matter.Common.keys(Examples).map(function(id){
|
||||
return {
|
||||
id: id,
|
||||
sourceLink: 'https://github.com/liabru/matter-js/blob/master/examples/' + id + '.js',
|
||||
name: Examples[id].title,
|
||||
init: Examples[id]
|
||||
};
|
||||
});
|
||||
|
||||
// start the requested tool
|
||||
var isCompare = window.location.search.indexOf('compare') >= 0;
|
||||
var isDev = __MATTER_IS_DEV__;
|
||||
if (isCompare) {
|
||||
compare(examples, isDev);
|
||||
} else {
|
||||
demo(examples, isDev);
|
||||
}
|
42945
package-lock.json
generated
42945
package-lock.json
generated
File diff suppressed because it is too large
Load diff
19
package.json
19
package.json
|
@ -22,27 +22,31 @@
|
|||
"devDependencies": {
|
||||
"conventional-changelog-cli": "^2.1.1",
|
||||
"eslint": "^6.8.0",
|
||||
"html-webpack-plugin": "^4.5.1",
|
||||
"jest": "^25.1.0",
|
||||
"jest-worker": "^24.9.0",
|
||||
"json-stringify-pretty-compact": "^2.0.0",
|
||||
"matter-tools": "^0.12.3",
|
||||
"matter-tools": "^0.13.0",
|
||||
"matter-wrap": "^0.2.0",
|
||||
"mock-require": "^3.0.3",
|
||||
"pathseg": "^1.2.0",
|
||||
"poly-decomp": "^0.3.0",
|
||||
"puppeteer-core": "^5.5.0",
|
||||
"terser-webpack-plugin": "^4.2.3",
|
||||
"webpack": "^4.46.0",
|
||||
"webpack-bundle-analyzer": "^4.4.0",
|
||||
"webpack-cli": "^3.3.11",
|
||||
"webpack-dev-server": "^3.11.1"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "webpack-dev-server --watch-content-base",
|
||||
"build": "webpack --mode=production & webpack --mode=production --env.MINIMIZE",
|
||||
"start": "npm run dev",
|
||||
"dev": "npm run serve -- --open",
|
||||
"serve": "webpack-dev-server --no-cache --mode development --config webpack.demo.config.js",
|
||||
"watch": "nodemon --watch webpack.demo.config.js --exec \"npm run serve\"",
|
||||
"build": "webpack --mode=production --no-hot --no-watch & webpack --mode=production --no-hot --no-watch --env.MINIMIZE",
|
||||
"build-alpha": "webpack --mode=production --env.ALPHA & webpack --mode=production --env.MINIMIZE --env.ALPHA",
|
||||
"build-examples": "webpack --config webpack.examples.config.js --mode=production & webpack --config webpack.examples.config.js --mode=production --env.MINIMIZE",
|
||||
"build-examples-alpha": "webpack --config webpack.examples.config.js --mode=production --env.ALPHA & webpack --config webpack.examples.config.js --mode=production --env.MINIMIZE --env.ALPHA",
|
||||
"build-demo": "mkdir -p demo/lib && cp node_modules/matter-tools/build/matter-tools.demo.js demo/lib & cp node_modules/matter-tools/build/matter-tools.gui.js demo/lib & cp node_modules/matter-tools/build/matter-tools.inspector.js demo/lib & cp node_modules/pathseg/pathseg.js demo/lib & cp node_modules/poly-decomp/build/decomp.js demo/lib & cp node_modules/matter-wrap/build/matter-wrap.js demo/lib",
|
||||
"lint": "eslint 'src/**/*.js' 'demo/js/Demo.js' 'demo/js/Compare.js' 'examples/*.js' 'webpack.*.js'",
|
||||
"build-demo": "rm -rf ./demo/js && webpack --no-hot --no-watch --config webpack.demo.config.js --mode=production && webpack --no-hot --no-watch --config webpack.demo.config.js --mode=production --env.MINIMIZE",
|
||||
"lint": "eslint 'src/**/*.js' 'demo/src/**/*.js' 'examples/*.js' 'webpack.*.js'",
|
||||
"doc": "yuidoc --config yuidoc.json --project-version $npm_package_version",
|
||||
"test": "npm run test-node",
|
||||
"test-all": "jest --no-cache",
|
||||
|
@ -55,7 +59,6 @@
|
|||
"preversion": "git checkout master && npm run lint && SAVE=true npm run test-all",
|
||||
"version": "git checkout -b release/$npm_package_version && npm run build"
|
||||
},
|
||||
"dependencies": {},
|
||||
"files": [
|
||||
"src",
|
||||
"build",
|
||||
|
|
|
@ -84,9 +84,11 @@ const runExamplesBrowser = async updates => {
|
|||
|
||||
// In the demo page context
|
||||
results[example] = await page.evaluate(async (example, updates) => {
|
||||
const demo = window.MatterDemoInstance;
|
||||
|
||||
// Set the current example
|
||||
MatterTools.Demo.setExampleById(MatterDemo, example);
|
||||
const instance = MatterDemo.example.instance;
|
||||
MatterTools.Demo.setExampleById(demo, example);
|
||||
const instance = demo.example.instance;
|
||||
let ticks = 0;
|
||||
|
||||
// Wait while running
|
||||
|
@ -103,7 +105,7 @@ const runExamplesBrowser = async updates => {
|
|||
|
||||
// Return results
|
||||
return {
|
||||
id: MatterDemo.example.id,
|
||||
id: demo.example.id,
|
||||
timestamp: instance.engine.timing.timestamp
|
||||
};
|
||||
}, example, updates);
|
||||
|
|
|
@ -10,32 +10,42 @@ const execSync = require('child_process').execSync;
|
|||
module.exports = (env = {}) => {
|
||||
const minimize = env.MINIMIZE || false;
|
||||
const alpha = env.ALPHA || false;
|
||||
const maxSize = minimize ? 100 * 1024 : 512 * 1024;
|
||||
const isDevServer = process.env.WEBPACK_DEV_SERVER;
|
||||
const sizeThreshold = minimize ? 100 * 1024 : 512 * 1024;
|
||||
|
||||
const commitHash = execSync('git rev-parse --short HEAD').toString().trim();
|
||||
const version = !alpha ? pkg.version : `${pkg.version}-alpha+${commitHash}`;
|
||||
const license = fs.readFileSync('LICENSE', 'utf8');
|
||||
const date = new Date().toISOString().slice(0, 10);
|
||||
const name = 'matter';
|
||||
const resolve = relativePath => path.resolve(__dirname, relativePath);
|
||||
|
||||
const alphaInfo = 'Experimental pre-release build.\n ';
|
||||
const banner =
|
||||
`${pkg.name} ${version} by @liabru ${date}
|
||||
`${pkg.name} ${version} by @liabru
|
||||
${alpha ? alphaInfo : ''}${pkg.homepage}
|
||||
License ${pkg.license}${!minimize ? '\n\n' + license : ''}`;
|
||||
|
||||
const entry = isDevServer ? './demo/js/Server.js' : './src/module/main.js';
|
||||
|
||||
const externals = isDevServer ?
|
||||
{
|
||||
'matter-js': {
|
||||
commonjs: 'matter-js',
|
||||
commonjs2: 'matter-js',
|
||||
amd: 'matter-js',
|
||||
root: 'Matter'
|
||||
}
|
||||
} :
|
||||
{
|
||||
return {
|
||||
entry: { 'matter': './src/module/main.js' },
|
||||
node: false,
|
||||
output: {
|
||||
library: 'Matter',
|
||||
libraryTarget: 'umd',
|
||||
umdNamedDefine: true,
|
||||
globalObject: 'this',
|
||||
path: resolve('./build'),
|
||||
filename: `[name]${alpha ? '.alpha' : ''}${minimize ? '.min' : ''}.js`
|
||||
},
|
||||
optimization: { minimize },
|
||||
performance: {
|
||||
maxEntrypointSize: sizeThreshold,
|
||||
maxAssetSize: sizeThreshold
|
||||
},
|
||||
plugins: [
|
||||
new webpack.BannerPlugin(banner),
|
||||
new webpack.DefinePlugin({
|
||||
__MATTER_VERSION__: JSON.stringify(version),
|
||||
})
|
||||
],
|
||||
externals: {
|
||||
'poly-decomp': {
|
||||
commonjs: 'poly-decomp',
|
||||
commonjs2: 'poly-decomp',
|
||||
|
@ -48,75 +58,6 @@ License ${pkg.license}${!minimize ? '\n\n' + license : ''}`;
|
|||
amd: 'matter-wrap',
|
||||
root: 'MatterWrap'
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
entry: { [name]: entry },
|
||||
output: {
|
||||
library: 'Matter',
|
||||
libraryTarget: 'umd',
|
||||
umdNamedDefine: true,
|
||||
globalObject: 'this',
|
||||
path: path.resolve(__dirname, './build'),
|
||||
filename: `[name]${alpha ? '.alpha' : ''}${minimize ? '.min' : ''}.js`
|
||||
},
|
||||
node: false,
|
||||
optimization: { minimize },
|
||||
performance: {
|
||||
maxEntrypointSize: maxSize,
|
||||
maxAssetSize: maxSize
|
||||
},
|
||||
plugins: [
|
||||
new webpack.BannerPlugin(banner),
|
||||
new webpack.DefinePlugin({
|
||||
__MATTER_VERSION__: JSON.stringify(!isDevServer ? version : '*'),
|
||||
})
|
||||
],
|
||||
externals,
|
||||
devServer: {
|
||||
contentBase: [
|
||||
path.resolve(__dirname, './demo'),
|
||||
path.resolve(__dirname, './examples'),
|
||||
path.resolve(__dirname, './node_modules/matter-tools/build'),
|
||||
path.resolve(__dirname, './node_modules/pathseg'),
|
||||
path.resolve(__dirname, './node_modules/matter-wrap/build')
|
||||
],
|
||||
watchContentBase: true,
|
||||
open: true,
|
||||
openPage: '',
|
||||
compress: true,
|
||||
overlay: true,
|
||||
port: 8000,
|
||||
proxy: {
|
||||
'/build': {
|
||||
target: 'http://localhost:8000/',
|
||||
pathRewrite: { '^/build' : '/' }
|
||||
},
|
||||
'/examples': {
|
||||
target: 'http://localhost:8000/',
|
||||
pathRewrite: { '^/examples' : '/' }
|
||||
},
|
||||
'/lib/matter-tools.demo.js': {
|
||||
target: 'http://localhost:8000/',
|
||||
pathRewrite: { '^/lib/matter-tools.demo.js' : '/matter-tools.demo.js' }
|
||||
},
|
||||
'/lib/matter-tools.inspector.js': {
|
||||
target: 'http://localhost:8000/',
|
||||
pathRewrite: { '^/lib/matter-tools.inspector.js' : '/matter-tools.inspector.js' }
|
||||
},
|
||||
'/lib/matter-tools.gui.js': {
|
||||
target: 'http://localhost:8000/',
|
||||
pathRewrite: { '^/lib/matter-tools.gui.js' : '/matter-tools.gui.js' }
|
||||
},
|
||||
'/lib/pathseg.js': {
|
||||
target: 'http://localhost:8000/',
|
||||
pathRewrite: { '^/lib/pathseg.js' : '/pathseg.js' }
|
||||
},
|
||||
'/lib/matter-wrap.js': {
|
||||
target: 'http://localhost:8000/',
|
||||
pathRewrite: { '^/lib/matter-wrap.js' : '/matter-wrap.js' }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
106
webpack.demo.config.js
Normal file
106
webpack.demo.config.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
/* eslint-env es6 */
|
||||
"use strict";
|
||||
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
const pkg = require('./package.json');
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const TerserPlugin = require('terser-webpack-plugin');
|
||||
|
||||
module.exports = (env = {}) => {
|
||||
const version = pkg.version;
|
||||
const analyze = env.ANALYZE || false;
|
||||
const devServer = Boolean(process.env.WEBPACK_DEV_SERVER);
|
||||
const minimize = !devServer;
|
||||
const sizeThreshold = 600 * 1024;
|
||||
|
||||
const publicPath = devServer ? '/' : './js';
|
||||
const devPath = './src/module/main.js';
|
||||
const buildPath = './build/matter.js';
|
||||
const resolve = relativePath => path.resolve(__dirname, relativePath);
|
||||
|
||||
const name = 'matter-demo';
|
||||
const banner =
|
||||
`${name} bundle ${version} by @liabru
|
||||
${pkg.homepage}
|
||||
License ${pkg.license}`;
|
||||
|
||||
return {
|
||||
entry: { [name]: './demo/src/index.js' },
|
||||
node: false,
|
||||
output: {
|
||||
library: 'MatterDemo',
|
||||
libraryTarget: 'umd',
|
||||
umdNamedDefine: true,
|
||||
globalObject: 'this',
|
||||
publicPath,
|
||||
path: resolve('./demo/js'),
|
||||
filename: `[name].[contenthash:6]${minimize ? '.min' : ''}.js`
|
||||
},
|
||||
resolve: {
|
||||
alias:{
|
||||
'matter-js': resolve(devPath),
|
||||
'MatterDev': resolve(devPath),
|
||||
'MatterBuild': resolve(
|
||||
devServer ? buildPath : devPath
|
||||
)
|
||||
}
|
||||
},
|
||||
optimization: {
|
||||
minimize,
|
||||
minimizer: [new TerserPlugin({ extractComments: false })],
|
||||
moduleIds: 'hashed',
|
||||
runtimeChunk: { name: `${name}.main` },
|
||||
splitChunks: {
|
||||
automaticNameDelimiter: '.',
|
||||
cacheGroups: {
|
||||
default: false,
|
||||
vendors: false,
|
||||
vendor: {
|
||||
chunks: 'all',
|
||||
enforce: true,
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
name: module => {
|
||||
if (devServer) {
|
||||
return `${name}.vendor`;
|
||||
}
|
||||
const parser = /[\\/]node_modules[\\/](.*?)([\\/]|$)/;
|
||||
const moduleName = module.context.match(parser)[1];
|
||||
return `${name}.${moduleName.replace('@', '')}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
performance: {
|
||||
maxEntrypointSize: sizeThreshold,
|
||||
maxAssetSize: sizeThreshold
|
||||
},
|
||||
plugins: [
|
||||
new webpack.BannerPlugin(banner),
|
||||
new webpack.DefinePlugin({
|
||||
__MATTER_VERSION__: JSON.stringify('*'),
|
||||
__MATTER_IS_DEV__: devServer
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: resolve('./demo/src/index.ejs'),
|
||||
filename: devServer ? 'index.html'
|
||||
: resolve('./demo/index.html'),
|
||||
inject: false,
|
||||
minify: false,
|
||||
publicPath
|
||||
})
|
||||
].concat(analyze ? [new BundleAnalyzerPlugin({
|
||||
openAnalyzer: true
|
||||
})] : []),
|
||||
devServer: {
|
||||
contentBase: [resolve('./demo')],
|
||||
watchContentBase: true,
|
||||
hot: false,
|
||||
compress: true,
|
||||
overlay: true,
|
||||
port: 8000
|
||||
}
|
||||
};
|
||||
};
|
|
@ -1,60 +0,0 @@
|
|||
/* eslint-env es6 */
|
||||
"use strict";
|
||||
|
||||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
const pkg = require('./package.json');
|
||||
const fs = require('fs');
|
||||
const execSync = require('child_process').execSync;
|
||||
|
||||
module.exports = (env = {}) => {
|
||||
const minimize = env.MINIMIZE || false;
|
||||
const alpha = env.ALPHA || false;
|
||||
const maxSize = minimize ? 100 * 1024 : 512 * 1024;
|
||||
|
||||
const commitHash = execSync('git rev-parse --short HEAD').toString().trim();
|
||||
const version = !alpha ? pkg.version : `${pkg.version}-alpha+${commitHash}`;
|
||||
const license = fs.readFileSync('LICENSE', 'utf8');
|
||||
const date = new Date().toISOString().slice(0, 10);
|
||||
const name = 'matter-js-examples';
|
||||
const alphaInfo = 'Experimental pre-release build.\n ';
|
||||
const banner =
|
||||
`${name} ${version} by @liabru ${date}
|
||||
${alpha ? alphaInfo : ''}${pkg.homepage}
|
||||
License ${pkg.license}${!minimize ? '\n\n' + license : ''}`;
|
||||
|
||||
return {
|
||||
entry: './examples/index.js',
|
||||
output: {
|
||||
library: 'Example',
|
||||
libraryTarget: 'umd',
|
||||
umdNamedDefine: true,
|
||||
globalObject: 'this',
|
||||
path: path.resolve(__dirname, './demo/js'),
|
||||
filename: `Examples${minimize ? '.min' : ''}.js`
|
||||
},
|
||||
node: false,
|
||||
optimization: { minimize },
|
||||
performance: {
|
||||
maxEntrypointSize: maxSize,
|
||||
maxAssetSize: maxSize
|
||||
},
|
||||
plugins: [
|
||||
new webpack.BannerPlugin(banner)
|
||||
],
|
||||
externals: {
|
||||
'matter-js': {
|
||||
commonjs: 'matter-js',
|
||||
commonjs2: 'matter-js',
|
||||
amd: 'matter-js',
|
||||
root: 'Matter'
|
||||
},
|
||||
'matter-wrap': {
|
||||
commonjs: 'matter-wrap',
|
||||
commonjs2: 'matter-wrap',
|
||||
amd: 'matter-wrap',
|
||||
root: 'MatterWrap'
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
Loading…
Reference in a new issue