Compare commits
1 Commits
greenkeepe
...
greenkeepe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52b3515b9b |
@@ -1,4 +1,3 @@
|
||||
dist/*
|
||||
node_modules/*
|
||||
playground/*
|
||||
tap-snapshots/*
|
||||
|
||||
16
.npmignore
16
.npmignore
@@ -1,16 +0,0 @@
|
||||
# Development files
|
||||
.eslintrc.js
|
||||
/.editorconfig
|
||||
/.eslintignore
|
||||
/.gitattributes
|
||||
/.github
|
||||
/.jsdoc.json
|
||||
/.travis.yml
|
||||
/test
|
||||
/webpack.config.js
|
||||
|
||||
# Build created files
|
||||
/playground
|
||||
|
||||
# Exclude already built packages from testing with npm pack
|
||||
/scratch-render-*.{tar,tgz}
|
||||
|
||||
35
package.json
35
package.json
@@ -10,7 +10,7 @@
|
||||
"url": "git+ssh://git@github.com/LLK/scratch-render.git"
|
||||
},
|
||||
"main": "./dist/node/scratch-render.js",
|
||||
"browser": "./src/index.js",
|
||||
"browser": "./dist/web/scratch-render.js",
|
||||
"scripts": {
|
||||
"build": "webpack --progress --colors",
|
||||
"docs": "jsdoc -c .jsdoc.json",
|
||||
@@ -26,34 +26,31 @@
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.23.1",
|
||||
"babel-eslint": "^8.2.1",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-polyfill": "^6.22.0",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"babel-preset-es2015": "^6.22.0",
|
||||
"base64-loader": "^1.0.0",
|
||||
"chromeless": "^1.5.1",
|
||||
"copy-webpack-plugin": "^4.5.1",
|
||||
"copy-webpack-plugin": "^4.0.1",
|
||||
"docdash": "^0.4.0",
|
||||
"eslint": "^4.6.1",
|
||||
"eslint-config-scratch": "^5.0.0",
|
||||
"gh-pages": "^1.2.0",
|
||||
"jsdoc": "^3.5.5",
|
||||
"json": "^9.0.4",
|
||||
"scratch-vm": "0.1.0-prerelease.1527254075",
|
||||
"tap": "^11.0.0",
|
||||
"travis-after-all": "^1.4.4",
|
||||
"uglifyjs-webpack-plugin": "^1.2.5",
|
||||
"webpack": "^4.8.0",
|
||||
"webpack-cli": "^2.0.15",
|
||||
"webpack-dev-server": "^3.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"gh-pages": "^1.0.0",
|
||||
"grapheme-breaker": "0.3.2",
|
||||
"hull.js": "0.2.10",
|
||||
"ify-loader": "1.0.4",
|
||||
"jsdoc": "^3.5.5",
|
||||
"json": "^9.0.4",
|
||||
"linebreak": "0.3.0",
|
||||
"minilog": "3.1.0",
|
||||
"raw-loader": "^0.5.1",
|
||||
"scratch-storage": "^0.4.0",
|
||||
"scratch-svg-renderer": "0.1.0-prerelease.20180531205843",
|
||||
"twgl.js": "4.4.0"
|
||||
"scratch-svg-renderer": "0.1.0-prerelease.20180423193917",
|
||||
"scratch-vm": "0.1.0-prerelease.1524520946",
|
||||
"tap": "^11.0.0",
|
||||
"travis-after-all": "^1.4.4",
|
||||
"twgl.js": "4.4.0",
|
||||
"webpack": "^3.10.0",
|
||||
"webpack-dev-server": "^3.1.4",
|
||||
"xml-escape": "1.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ const ShaderManager = require('./ShaderManager');
|
||||
const SVGSkin = require('./SVGSkin');
|
||||
const SVGTextBubble = require('./util/svg-text-bubble');
|
||||
const EffectTransform = require('./EffectTransform');
|
||||
const log = require('./util/log');
|
||||
|
||||
const __isTouchingDrawablesPoint = twgl.v3.create();
|
||||
const __candidatesBounds = new Rectangle();
|
||||
@@ -121,22 +120,6 @@ class RenderWebGL extends EventEmitter {
|
||||
/** @type {Array<int>} */
|
||||
this._drawList = [];
|
||||
|
||||
// A list of layer group names in the order they should appear
|
||||
// from furthest back to furthest in front.
|
||||
/** @type {Array<String>} */
|
||||
this._groupOrdering = [];
|
||||
|
||||
/**
|
||||
* @typedef LayerGroup
|
||||
* @property {int} groupIndex The relative position of this layer group in the group ordering
|
||||
* @property {int} drawListOffset The absolute position of this layer group in the draw list
|
||||
* This number gets updated as drawables get added to or deleted from the draw list.
|
||||
*/
|
||||
|
||||
// Map of group name to layer group
|
||||
/** @type {Object.<string, LayerGroup>} */
|
||||
this._layerGroups = {};
|
||||
|
||||
/** @type {int} */
|
||||
this._nextDrawableId = RenderConstants.ID_NONE + 1;
|
||||
|
||||
@@ -321,7 +304,7 @@ class RenderWebGL extends EventEmitter {
|
||||
/**
|
||||
* Update an existing bitmap skin, or create a bitmap skin if the previous skin was not bitmap.
|
||||
* @param {!int} skinId the ID for the skin to change.
|
||||
* @param {!ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} imgData - new contents for this skin.
|
||||
* @param {!string} imgData - new bitmap to use.
|
||||
* @param {!number} bitmapResolution - the resolution scale for a bitmap costume.
|
||||
* @param {?Array<number>} rotationCenter Optional: rotation center of the skin. If not supplied, the center of the
|
||||
* skin will be used
|
||||
@@ -377,100 +360,31 @@ class RenderWebGL extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Create a new Drawable and add it to the scene.
|
||||
* @param {string} group Layer group to add the drawable to
|
||||
* @returns {int} The ID of the new Drawable.
|
||||
*/
|
||||
createDrawable (group) {
|
||||
if (!group || !this._layerGroups.hasOwnProperty(group)) {
|
||||
log.warn('Cannot create a drawable without a known layer group');
|
||||
return;
|
||||
}
|
||||
createDrawable () {
|
||||
const drawableID = this._nextDrawableId++;
|
||||
const drawable = new Drawable(drawableID);
|
||||
this._allDrawables[drawableID] = drawable;
|
||||
this._addToDrawList(drawableID, group);
|
||||
this._drawList.push(drawableID);
|
||||
|
||||
drawable.skin = null;
|
||||
|
||||
return drawableID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the layer group ordering for the renderer.
|
||||
* @param {Array<string>} groupOrdering The ordered array of layer group
|
||||
* names
|
||||
*/
|
||||
setLayerGroupOrdering (groupOrdering) {
|
||||
this._groupOrdering = groupOrdering;
|
||||
for (let i = 0; i < this._groupOrdering.length; i++) {
|
||||
this._layerGroups[this._groupOrdering[i]] = {
|
||||
groupIndex: i,
|
||||
drawListOffset: 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
_addToDrawList (drawableID, group) {
|
||||
const currentLayerGroup = this._layerGroups[group];
|
||||
const currentGroupOrderingIndex = currentLayerGroup.groupIndex;
|
||||
|
||||
const drawListOffset = this._endIndexForKnownLayerGroup(currentLayerGroup);
|
||||
this._drawList.splice(drawListOffset, 0, drawableID);
|
||||
|
||||
this._updateOffsets('add', currentGroupOrderingIndex);
|
||||
}
|
||||
|
||||
_updateOffsets (updateType, currentGroupOrderingIndex) {
|
||||
for (let i = currentGroupOrderingIndex + 1; i < this._groupOrdering.length; i++) {
|
||||
const laterGroupName = this._groupOrdering[i];
|
||||
if (updateType === 'add') {
|
||||
this._layerGroups[laterGroupName].drawListOffset++;
|
||||
} else if (updateType === 'delete'){
|
||||
this._layerGroups[laterGroupName].drawListOffset--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Given a layer group, return the index where it ends (non-inclusive),
|
||||
// e.g. the returned index does not have a drawable from this layer group in it)
|
||||
_endIndexForKnownLayerGroup (layerGroup) {
|
||||
const groupIndex = layerGroup.groupIndex;
|
||||
if (groupIndex === this._groupOrdering.length - 1) {
|
||||
return this._drawList.length;
|
||||
}
|
||||
return this._layerGroups[this._groupOrdering[groupIndex + 1]].drawListOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy a Drawable, removing it from the scene.
|
||||
* @param {int} drawableID The ID of the Drawable to remove.
|
||||
* @param {string} group Group name that the drawable belongs to
|
||||
*/
|
||||
destroyDrawable (drawableID, group) {
|
||||
if (!group || !this._layerGroups.hasOwnProperty(group)) {
|
||||
log.warn('Cannot destroy drawable without known layer group.');
|
||||
return;
|
||||
}
|
||||
destroyDrawable (drawableID) {
|
||||
const drawable = this._allDrawables[drawableID];
|
||||
drawable.dispose();
|
||||
delete this._allDrawables[drawableID];
|
||||
|
||||
const currentLayerGroup = this._layerGroups[group];
|
||||
const endIndex = this._endIndexForKnownLayerGroup(currentLayerGroup);
|
||||
|
||||
let index = currentLayerGroup.drawListOffset;
|
||||
while (index < endIndex) {
|
||||
if (this._drawList[index] === drawableID) {
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
if (index < endIndex) {
|
||||
let index;
|
||||
while ((index = this._drawList.indexOf(drawableID)) >= 0) {
|
||||
this._drawList.splice(index, 1);
|
||||
this._updateOffsets('delete', currentLayerGroup.groupIndex);
|
||||
} else {
|
||||
log.warn('Could not destroy drawable that could not be found in layer group.');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,55 +397,28 @@ class RenderWebGL extends EventEmitter {
|
||||
* "go to front": setDrawableOrder(id, Infinity);
|
||||
* @param {int} drawableID ID of Drawable to reorder.
|
||||
* @param {number} order New absolute order or relative order adjusment.
|
||||
* @param {string=} group Name of layer group drawable belongs to.
|
||||
* Reordering will not take place if drawable cannot be found within the bounds
|
||||
* of the layer group.
|
||||
* @param {boolean=} optIsRelative If set, `order` refers to a relative change.
|
||||
* @param {number=} optMin If set, order constrained to be at least `optMin`.
|
||||
* @return {?number} New order if changed, or null.
|
||||
*/
|
||||
setDrawableOrder (drawableID, order, group, optIsRelative, optMin) {
|
||||
if (!group || !this._layerGroups.hasOwnProperty(group)) {
|
||||
log.warn('Cannot set the order of a drawable without a known layer group.');
|
||||
return;
|
||||
}
|
||||
|
||||
const currentLayerGroup = this._layerGroups[group];
|
||||
const startIndex = currentLayerGroup.drawListOffset;
|
||||
const endIndex = this._endIndexForKnownLayerGroup(currentLayerGroup);
|
||||
|
||||
let oldIndex = startIndex;
|
||||
while (oldIndex < endIndex) {
|
||||
if (this._drawList[oldIndex] === drawableID) {
|
||||
break;
|
||||
}
|
||||
oldIndex++;
|
||||
}
|
||||
|
||||
if (oldIndex < endIndex) {
|
||||
setDrawableOrder (drawableID, order, optIsRelative, optMin) {
|
||||
const oldIndex = this._drawList.indexOf(drawableID);
|
||||
if (oldIndex >= 0) {
|
||||
// Remove drawable from the list.
|
||||
if (order === 0) {
|
||||
return oldIndex;
|
||||
}
|
||||
|
||||
const _ = this._drawList.splice(oldIndex, 1)[0];
|
||||
const drawable = this._drawList.splice(oldIndex, 1)[0];
|
||||
// Determine new index.
|
||||
let newIndex = order;
|
||||
if (optIsRelative) {
|
||||
newIndex += oldIndex;
|
||||
}
|
||||
|
||||
const possibleMin = (optMin || 0) + startIndex;
|
||||
const min = (possibleMin >= startIndex && possibleMin < endIndex) ? possibleMin : startIndex;
|
||||
newIndex = Math.max(newIndex, min);
|
||||
|
||||
newIndex = Math.min(newIndex, endIndex);
|
||||
|
||||
if (optMin) {
|
||||
newIndex = Math.max(newIndex, optMin);
|
||||
}
|
||||
newIndex = Math.max(newIndex, 0);
|
||||
// Insert at new index.
|
||||
this._drawList.splice(newIndex, 0, drawableID);
|
||||
return newIndex;
|
||||
this._drawList.splice(newIndex, 0, drawable);
|
||||
return this._drawList.indexOf(drawable);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -59,11 +59,11 @@ class Silhouette {
|
||||
const height = this._height = canvas.height = bitmapData.height;
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.drawImage(bitmapData, 0, 0, width, height);
|
||||
if (!(width && height)) {
|
||||
return;
|
||||
}
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
ctx.drawImage(bitmapData, 0, 0, width, height);
|
||||
const imageData = ctx.getImageData(0, 0, width, height);
|
||||
|
||||
this._data = new Uint8ClampedArray(imageData.data.length / 4);
|
||||
@@ -79,7 +79,6 @@ class Silhouette {
|
||||
* @return {boolean} If the nearest pixel has an alpha value.
|
||||
*/
|
||||
isTouchingNearest (vec) {
|
||||
if (!this._data) return;
|
||||
return getPoint(
|
||||
this,
|
||||
Math.round(vec[0] * (this._width - 1)),
|
||||
@@ -94,7 +93,6 @@ class Silhouette {
|
||||
* @return {boolean} Any of the pixels have some alpha.
|
||||
*/
|
||||
isTouchingLinear (vec) {
|
||||
if (!this._data) return;
|
||||
const x = Math.floor(vec[0] * (this._width - 1));
|
||||
const y = Math.floor(vec[1] * (this._height - 1));
|
||||
return getPoint(this, x, y) > 0 ||
|
||||
|
||||
@@ -38,16 +38,15 @@
|
||||
var canvas = document.getElementById('scratch-stage');
|
||||
var fudge = 90;
|
||||
var renderer = new ScratchRender(canvas);
|
||||
renderer.setLayerGroupOrdering(['group1']);
|
||||
|
||||
var drawableID = renderer.createDrawable('group1');
|
||||
var drawableID = renderer.createDrawable();
|
||||
renderer.updateDrawableProperties(drawableID, {
|
||||
position: [0, 0],
|
||||
scale: [100, 100],
|
||||
direction: 90
|
||||
});
|
||||
|
||||
var drawableID2 = renderer.createDrawable('group1');
|
||||
var drawableID2 = renderer.createDrawable();
|
||||
var wantBitmapSkin = false;
|
||||
|
||||
// Bitmap (squirrel)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
const minilog = require('minilog');
|
||||
minilog.enable();
|
||||
|
||||
module.exports = minilog('scratch-render');
|
||||
@@ -1,30 +1,17 @@
|
||||
const SVGTextWrapper = require('./svg-text-wrapper');
|
||||
const SvgRenderer = require('scratch-svg-renderer').SVGRenderer;
|
||||
const xmlescape = require('xml-escape');
|
||||
|
||||
const MAX_LINE_LENGTH = 170;
|
||||
const MIN_WIDTH = 50;
|
||||
const STROKE_WIDTH = 4;
|
||||
|
||||
class SVGTextBubble {
|
||||
constructor () {
|
||||
this.svgRenderer = new SvgRenderer();
|
||||
this.svgTextWrapper = new SVGTextWrapper(this.makeSvgTextElement);
|
||||
this.svgTextWrapper = new SVGTextWrapper();
|
||||
this._textSizeCache = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {SVGElement} an SVG text node with the properties that we want for speech bubbles.
|
||||
*/
|
||||
makeSvgTextElement () {
|
||||
const svgText = document.createElementNS('http://www.w3.org/2000/svg', 'text');
|
||||
svgText.setAttribute('alignment-baseline', 'text-before-edge');
|
||||
svgText.setAttribute('font-size', '14');
|
||||
svgText.setAttribute('fill', '#575E75');
|
||||
// TODO Do we want to use the new default sans font instead of Helvetica?
|
||||
svgText.setAttribute('font-family', 'Helvetica');
|
||||
return svgText;
|
||||
}
|
||||
|
||||
_speechBubble (w, h, radius, pointsLeft) {
|
||||
let pathString = `
|
||||
M 0 ${radius}
|
||||
@@ -58,7 +45,7 @@ class SVGTextBubble {
|
||||
<path
|
||||
d="${pathString}"
|
||||
stroke="rgba(0, 0, 0, 0.15)"
|
||||
stroke-width="${STROKE_WIDTH}"
|
||||
stroke-width="4"
|
||||
fill="rgba(0, 0, 0, 0.15)"
|
||||
stroke-line-join="round"
|
||||
/>
|
||||
@@ -114,7 +101,7 @@ class SVGTextBubble {
|
||||
rx="${rx}" ry="${ry}"
|
||||
fill="rgba(0, 0, 0, 0.15)"
|
||||
stroke="rgba(0, 0, 0, 0.15)"
|
||||
stroke-width="${STROKE_WIDTH}"
|
||||
stroke-width="4"
|
||||
/>
|
||||
<ellipse
|
||||
cx="${cx}" cy="${cy}"
|
||||
@@ -138,8 +125,7 @@ class SVGTextBubble {
|
||||
|
||||
return `
|
||||
<g>
|
||||
<path d="${pathString}" stroke="rgba(0, 0, 0, 0.15)" stroke-width="${STROKE_WIDTH}"
|
||||
fill="rgba(0, 0, 0, 0.15)" />
|
||||
<path d="${pathString}" stroke="rgba(0, 0, 0, 0.15)" stroke-width="4" fill="rgba(0, 0, 0, 0.15)" />
|
||||
<path d="${pathString}" stroke="none" fill="white" />
|
||||
${ellipses.join('\n')}
|
||||
</g>`;
|
||||
@@ -147,38 +133,29 @@ class SVGTextBubble {
|
||||
|
||||
|
||||
_getTextSize () {
|
||||
const svgString = this._wrapSvgFragment(this._textFragment);
|
||||
const svgString = this._wrapSvgFragment(this._textFragment());
|
||||
if (!this._textSizeCache[svgString]) {
|
||||
this._textSizeCache[svgString] = this.svgRenderer.measure(svgString);
|
||||
}
|
||||
return this._textSizeCache[svgString];
|
||||
}
|
||||
|
||||
_wrapSvgFragment (fragment, width, height) {
|
||||
let svgString = `<svg xmlns="http://www.w3.org/2000/svg" version="1.1"`;
|
||||
if (width && height) {
|
||||
const fullWidth = width + STROKE_WIDTH;
|
||||
const fullHeight = height + STROKE_WIDTH + 12;
|
||||
svgString = `${svgString} viewBox="
|
||||
${-STROKE_WIDTH / 2} ${-STROKE_WIDTH / 2} ${fullWidth} ${fullHeight}"
|
||||
width="${fullWidth}" height="${fullHeight}">`;
|
||||
} else {
|
||||
svgString = `${svgString}>`;
|
||||
}
|
||||
svgString = `${svgString} ${fragment} </svg>`;
|
||||
return svgString;
|
||||
_wrapSvgFragment (fragment) {
|
||||
return `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
|
||||
${fragment}
|
||||
</svg>
|
||||
`;
|
||||
}
|
||||
|
||||
_buildTextFragment (text) {
|
||||
const textNode = this.svgTextWrapper.wrapText(MAX_LINE_LENGTH, text);
|
||||
const serializer = new XMLSerializer();
|
||||
return serializer.serializeToString(textNode);
|
||||
_textFragment () {
|
||||
return `<text fill="#575E75">${xmlescape(this.lines.join('\n'))}</text>`;
|
||||
}
|
||||
|
||||
buildString (type, text, pointsLeft) {
|
||||
this.type = type;
|
||||
this.pointsLeft = pointsLeft;
|
||||
this._textFragment = this._buildTextFragment(text);
|
||||
this.lines = this.svgTextWrapper.wrapText(MAX_LINE_LENGTH, text);
|
||||
|
||||
let fragment = '';
|
||||
|
||||
@@ -192,8 +169,8 @@ class SVGTextBubble {
|
||||
} else {
|
||||
fragment += this._thinkBubble(fullWidth, fullHeight, radius, this.pointsLeft);
|
||||
}
|
||||
fragment += `<g transform="translate(${padding - x}, ${padding - y})">${this._textFragment}</g>`;
|
||||
return this._wrapSvgFragment(fragment, fullWidth, fullHeight);
|
||||
fragment += `<g transform="translate(${padding - x}, ${padding - y})">${this._textFragment()}</g>`;
|
||||
return this._wrapSvgFragment(fragment);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,9 @@ const TextWrapper = require('./text-wrapper');
|
||||
* For use with TextWrapper.
|
||||
*/
|
||||
class SVGMeasurementProvider {
|
||||
/**
|
||||
* @param {function} makeTextElement - provides a text node of an SVGElement
|
||||
* with the style of the text to be wrapped.
|
||||
*/
|
||||
constructor (makeTextElement) {
|
||||
constructor () {
|
||||
this._svgRoot = null;
|
||||
this._cache = {};
|
||||
this.makeTextElement = makeTextElement;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,7 +61,13 @@ class SVGMeasurementProvider {
|
||||
|
||||
const svgRoot = document.createElementNS(svgNamespace, 'svg');
|
||||
const svgGroup = document.createElementNS(svgNamespace, 'g');
|
||||
const svgText = this.makeTextElement();
|
||||
const svgText = document.createElementNS(svgNamespace, 'text');
|
||||
|
||||
// Normalize text attributes to match what the svg-renderer does.
|
||||
// @TODO This code should be shared with the svg-renderer.
|
||||
svgText.setAttribute('alignment-baseline', 'text-before-edge');
|
||||
svgText.setAttribute('font-size', '14');
|
||||
svgText.setAttribute('font-family', 'Helvetica');
|
||||
|
||||
// hide from the user, including screen readers
|
||||
svgRoot.setAttribute('style', 'position:absolute;visibility:hidden');
|
||||
@@ -95,32 +96,8 @@ class SVGMeasurementProvider {
|
||||
* TextWrapper specialized for SVG text.
|
||||
*/
|
||||
class SVGTextWrapper extends TextWrapper {
|
||||
/**
|
||||
* @param {function} makeTextElement - provides a text node of an SVGElement
|
||||
* with the style of the text to be wrapped.
|
||||
*/
|
||||
constructor (makeTextElement) {
|
||||
super(new SVGMeasurementProvider(makeTextElement));
|
||||
this.makeTextElement = makeTextElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the provided text into lines restricted to a maximum width. See Unicode Standard Annex (UAX) #14.
|
||||
* @param {number} maxWidth - the maximum allowed width of a line.
|
||||
* @param {string} text - the text to be wrapped. Will be split on whitespace.
|
||||
* @returns {SVGElement} wrapped text node
|
||||
*/
|
||||
wrapText (maxWidth, text) {
|
||||
const lines = super.wrapText(maxWidth, text);
|
||||
const textElement = this.makeTextElement();
|
||||
for (const line of lines) {
|
||||
const tspanNode = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
|
||||
tspanNode.setAttribute('x', '0');
|
||||
tspanNode.setAttribute('dy', '1.2em');
|
||||
tspanNode.textContent = line;
|
||||
textElement.appendChild(tspanNode);
|
||||
}
|
||||
return textElement;
|
||||
constructor () {
|
||||
super(new SVGMeasurementProvider());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const LineBreaker = require('!ify-loader!linebreak');
|
||||
const GraphemeBreaker = require('!ify-loader!grapheme-breaker');
|
||||
const LineBreaker = require('linebreak');
|
||||
const GraphemeBreaker = require('grapheme-breaker');
|
||||
|
||||
/**
|
||||
* Tell this text wrapper to use a specific measurement provider.
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
/* IMPORTANT
|
||||
* This snapshot file is auto-generated, but designed for humans.
|
||||
* It should be checked into source control and tracked carefully.
|
||||
* Re-generate by setting TAP_SNAPSHOT=1 and running tests.
|
||||
* Make sure to inspect the output below. Do not ignore changes!
|
||||
*/
|
||||
'use strict'
|
||||
exports[`test/integration/scratch-tests.js TAP bubble snapshot > bubble-text-snapshot 1`] = `
|
||||
<text xmlns="http://www.w3.org/2000/svg" alignment-baseline="text-before-edge" font-size="14" fill="#575E75" font-family="Helvetica"><tspan x="0" dy="1.2em"><e*&%$&^$></!abc'></tspan></text>
|
||||
`
|
||||
@@ -1,4 +1,4 @@
|
||||
/* global vm, render, Promise */
|
||||
/* global vm, Promise */
|
||||
const {Chromeless} = require('chromeless');
|
||||
const test = require('tap').test;
|
||||
const path = require('path');
|
||||
@@ -35,11 +35,9 @@ const testFile = file => test(file, async t => {
|
||||
return Promise.resolve()
|
||||
.then(async () => {
|
||||
// waiting for all threads to complete, then we return
|
||||
while (vm.runtime.threads.some(thread => vm.runtime.isActiveThread(thread))) {
|
||||
while (vm.runtime.threads.length > 0) {
|
||||
if ((Date.now() - startTime) >= TIMEOUT) {
|
||||
// if we push the message after end, the failure from tap is not very useful:
|
||||
// "not ok test after end() was called"
|
||||
messages.unshift(`fail Threads still running after ${TIMEOUT}ms`);
|
||||
messages.push(`fail Threads still running after ${TIMEOUT}ms`);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -101,16 +99,6 @@ const testFile = file => test(file, async t => {
|
||||
}
|
||||
});
|
||||
|
||||
const testBubbles = () => test('bubble snapshot', async t => {
|
||||
const bubbleSvg = await chromeless.goto(`file://${indexHTML}`)
|
||||
.evaluate(() => {
|
||||
const testString = '<e*&%$&^$></!abc\'>';
|
||||
return render._svgTextBubble._buildTextFragment(testString);
|
||||
});
|
||||
t.matchSnapshot(bubbleSvg, 'bubble-text-snapshot');
|
||||
t.end();
|
||||
});
|
||||
|
||||
// immediately invoked async function to let us wait for each test to finish before starting the next.
|
||||
(async () => {
|
||||
const files = fs.readdirSync(testDir())
|
||||
@@ -120,8 +108,6 @@ const testBubbles = () => test('bubble snapshot', async t => {
|
||||
await testFile(file);
|
||||
}
|
||||
|
||||
await testBubbles();
|
||||
|
||||
// close the browser window we used
|
||||
await chromeless.end();
|
||||
})();
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const path = require('path');
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
|
||||
const webpack = require('webpack');
|
||||
|
||||
const base = {
|
||||
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
|
||||
devServer: {
|
||||
contentBase: false,
|
||||
host: '0.0.0.0',
|
||||
@@ -19,19 +18,21 @@ const base = {
|
||||
test: /\.js$/,
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [['env', {targets: {browsers: ['last 3 versions', 'Safari >= 8', 'iOS >= 8']}}]]
|
||||
presets: ['es2015']
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /node_modules[\\/](linebreak|grapheme-breaker)[\\/].*\.js$/,
|
||||
loader: 'ify-loader'
|
||||
}
|
||||
]
|
||||
},
|
||||
optimization: {
|
||||
minimizer: [
|
||||
new UglifyJsPlugin({
|
||||
include: /\.min\.js$/
|
||||
})
|
||||
]
|
||||
},
|
||||
plugins: []
|
||||
plugins: process.env.NODE_ENV === 'production' ? [
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
include: /\.min\.js$/,
|
||||
minimize: true
|
||||
})
|
||||
] : []
|
||||
};
|
||||
|
||||
module.exports = [
|
||||
@@ -80,14 +81,6 @@ module.exports = [
|
||||
libraryTarget: 'commonjs2',
|
||||
path: path.resolve('dist', 'node'),
|
||||
filename: '[name].js'
|
||||
},
|
||||
externals: {
|
||||
'!ify-loader!grapheme-breaker': 'grapheme-breaker',
|
||||
'!ify-loader!linebreak': 'linebreak',
|
||||
'hull.js': true,
|
||||
'scratch-svg-renderer': true,
|
||||
'twgl.js': true,
|
||||
'xml-escape': true
|
||||
}
|
||||
})
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user