kopia lustrzana https://github.com/backface/turtlestitch
2410 wiersze
60 KiB
JavaScript
2410 wiersze
60 KiB
JavaScript
/*
|
|
|
|
symbols.js
|
|
|
|
graphical GUI-symbols for for morphic.js and Snap!
|
|
|
|
written by Jens Mönig
|
|
jens@moenig.org
|
|
|
|
Copyright (C) 2021 by Jens Mönig
|
|
|
|
This file is part of Snap!.
|
|
|
|
Snap! is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of
|
|
the License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
prerequisites:
|
|
--------------
|
|
needs morphic.js
|
|
|
|
|
|
credits:
|
|
--------
|
|
additional symbols have been contributed by members of the Snap!
|
|
open-source community, especially by Bernat Romagosa
|
|
|
|
*/
|
|
|
|
/*global modules, Morph, Point, radians, ZERO, BLACK*/
|
|
|
|
// Global stuff ////////////////////////////////////////////////////////
|
|
|
|
modules.symbols = '2021-March-03';
|
|
|
|
var SymbolMorph;
|
|
|
|
// SymbolMorph //////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
I display graphical symbols, such as special letters. I have been
|
|
called into existence out of frustration about not being able to
|
|
consistently use Unicode characters to the same ends.
|
|
|
|
Symbols can also display costumes, if one is specified in lieu
|
|
of a name property, although this feature is currently not being
|
|
used because of asynchronous image loading issues.
|
|
*/
|
|
|
|
// SymbolMorph inherits from Morph:
|
|
|
|
SymbolMorph.prototype = new Morph();
|
|
SymbolMorph.prototype.constructor = SymbolMorph;
|
|
SymbolMorph.uber = Morph.prototype;
|
|
|
|
// SymbolMorph available symbols:
|
|
|
|
SymbolMorph.prototype.names = [
|
|
'square',
|
|
'pointRight',
|
|
'stepForward',
|
|
'gears',
|
|
'gearPartial',
|
|
'gearBig',
|
|
'file',
|
|
'fullScreen',
|
|
'grow',
|
|
'normalScreen',
|
|
'shrink',
|
|
'smallStage',
|
|
'normalStage',
|
|
'turtle',
|
|
'turtleOutline',
|
|
'stage',
|
|
'pause',
|
|
'flag',
|
|
'octagon',
|
|
'cloud',
|
|
'cloudGradient',
|
|
'cloudOutline',
|
|
'turnRight',
|
|
'turnLeft',
|
|
'turnAround',
|
|
'storage',
|
|
'poster',
|
|
'flash',
|
|
'brush',
|
|
'tick',
|
|
'checkedBox',
|
|
'rectangle',
|
|
'rectangleSolid',
|
|
'circle',
|
|
'circleSolid',
|
|
'ellipse',
|
|
'line',
|
|
'cross',
|
|
'crosshairs',
|
|
'paintbucket',
|
|
'eraser',
|
|
'pipette',
|
|
'speechBubble',
|
|
'speechBubbleOutline',
|
|
'loop',
|
|
'turnBack',
|
|
'turnForward',
|
|
'arrowUp',
|
|
'arrowUpOutline',
|
|
'arrowUpThin',
|
|
'arrowUpDownThin',
|
|
'arrowLeft',
|
|
'arrowLeftOutline',
|
|
'arrowLeftThin',
|
|
'arrowLeftRightThin',
|
|
'arrowDown',
|
|
'arrowDownOutline',
|
|
'arrowDownThin',
|
|
'arrowRight',
|
|
'arrowRightOutline',
|
|
'arrowRightThin',
|
|
'robot',
|
|
'magnifyingGlass',
|
|
'magnifierOutline',
|
|
'selection',
|
|
'polygon',
|
|
'closedBrush',
|
|
'notes',
|
|
'camera',
|
|
'location',
|
|
'footprints',
|
|
'keyboard',
|
|
'keyboardFilled',
|
|
'globe',
|
|
'globeBig',
|
|
'list',
|
|
'flipVertical',
|
|
'flipHorizontal',
|
|
'trash',
|
|
'trashFull'
|
|
];
|
|
|
|
// SymbolMorph instance creation:
|
|
|
|
function SymbolMorph(name, size, color, shadowOffset, shadowColor) {
|
|
this.init(name, size, color, shadowOffset, shadowColor);
|
|
}
|
|
|
|
SymbolMorph.prototype.init = function (
|
|
name,
|
|
size,
|
|
color,
|
|
shadowOffset,
|
|
shadowColor
|
|
) {
|
|
this.isProtectedLabel = false; // participate in zebraing
|
|
this.isReadOnly = true;
|
|
this.name = name || 'square';
|
|
this.size = size || 50;
|
|
this.shadowOffset = shadowOffset || ZERO;
|
|
this.shadowColor = shadowColor || null;
|
|
SymbolMorph.uber.init.call(this);
|
|
this.color = color || BLACK;
|
|
this.fixLayout();
|
|
this.rerender();
|
|
};
|
|
|
|
// SymbolMorph string representation: 'a SymbolMorph: "square"'
|
|
|
|
SymbolMorph.prototype.toString = function () {
|
|
return 'a ' +
|
|
(this.constructor.name ||
|
|
this.constructor.toString().split(' ')[1].split('(')[0]) +
|
|
': "' +
|
|
this.name +
|
|
'" ' +
|
|
this.bounds;
|
|
};
|
|
|
|
// SymbolMorph zebra coloring:
|
|
|
|
SymbolMorph.prototype.setLabelColor = function (
|
|
textColor,
|
|
shadowColor,
|
|
shadowOffset
|
|
) {
|
|
this.shadowOffset = shadowOffset || new Point();
|
|
this.shadowColor = shadowColor;
|
|
this.setColor(textColor);
|
|
};
|
|
|
|
// SymbolMorph dynamic coloring:
|
|
|
|
SymbolMorph.prototype.getShadowRenderColor = function () {
|
|
// answer the shadow rendering color, can be overridden for my children
|
|
return this.shadowColor;
|
|
};
|
|
|
|
// SymbolMorph layout:
|
|
|
|
SymbolMorph.prototype.setExtent = function (aPoint) {
|
|
if (this.size === aPoint.y) {return; }
|
|
this.changed();
|
|
this.size = aPoint.y;
|
|
this.fixLayout();
|
|
this.rerender();
|
|
};
|
|
|
|
SymbolMorph.prototype.fixLayout = function () {
|
|
// determine my extent
|
|
this.bounds.setWidth(this.symbolWidth() + Math.abs(this.shadowOffset.x));
|
|
this.bounds.setHeight(this.size + Math.abs(this.shadowOffset.y));
|
|
};
|
|
|
|
// SymbolMorph displaying:
|
|
|
|
SymbolMorph.prototype.render = function (ctx) {
|
|
var sx = this.shadowOffset.x < 0 ? 0 : this.shadowOffset.x,
|
|
sy = this.shadowOffset.y < 0 ? 0 : this.shadowOffset.y,
|
|
x = this.shadowOffset.x < 0 ? Math.abs(this.shadowOffset.x) : 0,
|
|
y = this.shadowOffset.y < 0 ? Math.abs(this.shadowOffset.y) : 0;
|
|
|
|
if (this.shadowColor) {
|
|
ctx.save();
|
|
ctx.translate(sx, sy);
|
|
this.renderShape(ctx, this.getShadowRenderColor());
|
|
ctx.restore();
|
|
}
|
|
ctx.save();
|
|
ctx.translate(x, y);
|
|
this.renderShape(ctx, this.getRenderColor());
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderShape = function (ctx, aColor) {
|
|
// private
|
|
switch (this.name) {
|
|
case 'square':
|
|
this.renderSymbolStop(ctx, aColor);
|
|
break;
|
|
case 'pointRight':
|
|
this.renderSymbolPointRight(ctx, aColor);
|
|
break;
|
|
case 'stepForward':
|
|
this.renderSymbolStepForward(ctx, aColor);
|
|
break;
|
|
case 'gears':
|
|
this.renderSymbolGears(ctx, aColor);
|
|
break;
|
|
case 'gearBig':
|
|
this.renderSymbolGearBig(ctx, aColor);
|
|
break;
|
|
case 'gearPartial':
|
|
this.renderSymbolGearPartial(ctx, aColor);
|
|
break;
|
|
case 'file':
|
|
this.renderSymbolFile(ctx, aColor);
|
|
break;
|
|
case 'fullScreen':
|
|
this.renderSymbolFullScreen(ctx, aColor);
|
|
break;
|
|
case 'grow':
|
|
this.renderSymbolGrow(ctx, aColor);
|
|
break;
|
|
case 'normalScreen':
|
|
this.renderSymbolNormalScreen(ctx, aColor);
|
|
break;
|
|
case 'smallStage':
|
|
this.renderSymbolSmallStage(ctx, aColor);
|
|
break;
|
|
case 'normalStage':
|
|
this.renderSymbolNormalStage(ctx, aColor);
|
|
break;
|
|
case 'shrink':
|
|
this.renderSymbolShrink(ctx, aColor);
|
|
break;
|
|
case 'turtle':
|
|
this.renderSymbolTurtle(ctx, aColor);
|
|
break;
|
|
case 'turtleOutline':
|
|
this.renderSymbolTurtleOutline(ctx, aColor);
|
|
break;
|
|
case 'stage':
|
|
this.renderSymbolStop(ctx, aColor);
|
|
break;
|
|
case 'pause':
|
|
this.renderSymbolPause(ctx, aColor);
|
|
break;
|
|
case 'flag':
|
|
this.renderSymbolFlag(ctx, aColor);
|
|
break;
|
|
case 'octagon':
|
|
this.renderSymbolOctagon(ctx, aColor);
|
|
break;
|
|
case 'cloud':
|
|
this.renderSymbolCloud(ctx, aColor);
|
|
break;
|
|
case 'cloudGradient':
|
|
this.renderSymbolCloudGradient(ctx, aColor);
|
|
break;
|
|
case 'cloudOutline':
|
|
this.renderSymbolCloudOutline(ctx, aColor);
|
|
break;
|
|
case 'turnRight':
|
|
this.renderSymbolTurnRight(ctx, aColor);
|
|
break;
|
|
case 'turnLeft':
|
|
this.renderSymbolTurnLeft(ctx, aColor);
|
|
break;
|
|
case 'turnAround':
|
|
this.renderSymbolTurnAround(ctx, aColor);
|
|
break;
|
|
case 'storage':
|
|
this.renderSymbolStorage(ctx, aColor);
|
|
break;
|
|
case 'poster':
|
|
this.renderSymbolPoster(ctx, aColor);
|
|
break;
|
|
case 'flash':
|
|
this.renderSymbolFlash(ctx, aColor);
|
|
break;
|
|
case 'brush':
|
|
this.renderSymbolBrush(ctx, aColor);
|
|
break;
|
|
case 'tick':
|
|
this.renderSymbolTick(ctx, aColor);
|
|
break;
|
|
case 'checkedBox':
|
|
this.renderSymbolCheckedBox(ctx, aColor);
|
|
break;
|
|
case 'rectangle':
|
|
this.renderSymbolRectangle(ctx, aColor);
|
|
break;
|
|
case 'rectangleSolid':
|
|
this.renderSymbolRectangleSolid(ctx, aColor);
|
|
break;
|
|
case 'circle':
|
|
this.renderSymbolCircle(ctx, aColor);
|
|
break;
|
|
case 'circleSolid':
|
|
this.renderSymbolCircleSolid(ctx, aColor);
|
|
break;
|
|
case 'ellipse':
|
|
this.renderSymbolCircle(ctx, aColor);
|
|
break;
|
|
case 'line':
|
|
this.renderSymbolLine(ctx, aColor);
|
|
break;
|
|
case 'cross':
|
|
this.renderSymbolCross(ctx, aColor);
|
|
break;
|
|
case 'crosshairs':
|
|
this.renderSymbolCrosshairs(ctx, aColor);
|
|
break;
|
|
case 'paintbucket':
|
|
this.renderSymbolPaintbucket(ctx, aColor);
|
|
break;
|
|
case 'eraser':
|
|
this.renderSymbolEraser(ctx, aColor);
|
|
break;
|
|
case 'pipette':
|
|
this.renderSymbolPipette(ctx, aColor);
|
|
break;
|
|
case 'speechBubble':
|
|
this.renderSymbolSpeechBubble(ctx, aColor);
|
|
break;
|
|
case 'speechBubbleOutline':
|
|
this.renderSymbolSpeechBubbleOutline(ctx, aColor);
|
|
break;
|
|
case 'loop':
|
|
this.renderSymbolLoop(ctx, aColor);
|
|
break;
|
|
case 'turnBack':
|
|
this.renderSymbolTurnBack(ctx, aColor);
|
|
break;
|
|
case 'turnForward':
|
|
this.renderSymbolTurnForward(ctx, aColor);
|
|
break;
|
|
case 'arrowUp':
|
|
this.renderSymbolArrowUp(ctx, aColor);
|
|
break;
|
|
case 'arrowUpOutline':
|
|
this.renderSymbolArrowUpOutline(ctx, aColor);
|
|
break;
|
|
case 'arrowUpThin':
|
|
this.renderSymbolArrowUpThin(ctx, aColor);
|
|
break;
|
|
case 'arrowUpDownThin':
|
|
this.renderSymbolArrowUpDownThin(ctx, aColor);
|
|
break;
|
|
case 'arrowLeft':
|
|
this.renderSymbolArrowLeft(ctx, aColor);
|
|
break;
|
|
case 'arrowLeftOutline':
|
|
this.renderSymbolArrowLeftOutline(ctx, aColor);
|
|
break;
|
|
case 'arrowLeftThin':
|
|
this.renderSymbolArrowLeftThin(ctx, aColor);
|
|
break;
|
|
case 'arrowLeftRightThin':
|
|
this.renderSymbolArrowLeftRightThin(ctx, aColor);
|
|
break;
|
|
case 'arrowDown':
|
|
this.renderSymbolArrowDown(ctx, aColor);
|
|
break;
|
|
case 'arrowDownOutline':
|
|
this.renderSymbolArrowDownOutline(ctx, aColor);
|
|
break;
|
|
case 'arrowDownThin':
|
|
this.renderSymbolArrowDownThin(ctx, aColor);
|
|
break;
|
|
case 'arrowRight':
|
|
this.renderSymbolArrowRight(ctx, aColor);
|
|
break;
|
|
case 'arrowRightOutline':
|
|
this.renderSymbolArrowRightOutline(ctx, aColor);
|
|
break;
|
|
case 'arrowRightThin':
|
|
this.renderSymbolArrowRightThin(ctx, aColor);
|
|
break;
|
|
case 'robot':
|
|
this.renderSymbolRobot(ctx, aColor);
|
|
break;
|
|
case 'magnifyingGlass':
|
|
this.renderSymbolMagnifyingGlass(ctx, aColor);
|
|
break;
|
|
case 'magnifierOutline':
|
|
this.renderSymbolMagnifierOutline(ctx, aColor);
|
|
break;
|
|
case 'selection':
|
|
this.renderSymbolSelection(ctx, aColor);
|
|
break;
|
|
case 'polygon':
|
|
this.renderSymbolOctagonOutline(ctx, aColor);
|
|
break;
|
|
case 'closedBrush':
|
|
this.renderSymbolClosedBrushPath(ctx, aColor);
|
|
break;
|
|
case 'notes':
|
|
this.renderSymbolNotes(ctx, aColor);
|
|
break;
|
|
case 'camera':
|
|
this.renderSymbolCamera(ctx, aColor);
|
|
break;
|
|
case 'location':
|
|
this.renderSymbolLocation(ctx, aColor);
|
|
break;
|
|
case 'footprints':
|
|
this.renderSymbolFootprints(ctx, aColor);
|
|
break;
|
|
case 'keyboard':
|
|
this.renderSymbolKeyboard(ctx, aColor);
|
|
break;
|
|
case 'keyboardFilled':
|
|
this.renderSymbolKeyboardFilled(ctx, aColor);
|
|
break;
|
|
case 'globe':
|
|
this.renderSymbolGlobe(ctx, aColor);
|
|
break;
|
|
case 'globeBig':
|
|
this.renderSymbolGlobeBig(ctx, aColor);
|
|
break;
|
|
case 'list':
|
|
this.renderSymbolList(ctx, aColor);
|
|
break;
|
|
case 'flipVertical':
|
|
this.renderSymbolFlipVertical(ctx, aColor);
|
|
break;
|
|
case 'flipHorizontal':
|
|
this.renderSymbolFlipHorizontal(ctx, aColor);
|
|
break;
|
|
case 'trash':
|
|
this.renderSymbolTrash(ctx, aColor);
|
|
break;
|
|
case 'trashFull':
|
|
this.renderSymbolTrashFull(ctx, aColor);
|
|
break;
|
|
default:
|
|
throw new Error('unknown symbol name: "' + this.name + '"');
|
|
}
|
|
};
|
|
|
|
SymbolMorph.prototype.symbolWidth = function () {
|
|
// private
|
|
var size = this.size;
|
|
|
|
switch (this.name) {
|
|
case 'pointRight':
|
|
return Math.sqrt(size * size - Math.pow(size / 2, 2));
|
|
case 'location':
|
|
return size * 0.6;
|
|
case 'flash':
|
|
case 'file':
|
|
case 'list':
|
|
return size * 0.8;
|
|
case 'smallStage':
|
|
case 'normalStage':
|
|
return size * 1.2;
|
|
case 'turtle':
|
|
case 'turtleOutline':
|
|
case 'stage':
|
|
return size * 1.3;
|
|
case 'cloud':
|
|
case 'cloudGradient':
|
|
case 'cloudOutline':
|
|
case 'turnBack':
|
|
case 'turnForward':
|
|
case 'keyboard':
|
|
case 'keyboardFilled':
|
|
return size * 1.6;
|
|
case 'turnRight':
|
|
case 'turnLeft':
|
|
return size / 3 * 2;
|
|
case 'loop':
|
|
return size * 2;
|
|
default:
|
|
return size;
|
|
}
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolStop = function (ctx, color) {
|
|
// draw a vertically centered square
|
|
ctx.fillStyle = color.toString();
|
|
ctx.fillRect(0, 0, this.symbolWidth(), this.size);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolPointRight = function (ctx, color) {
|
|
// draw a right-pointing, equilateral triangle
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 0);
|
|
ctx.lineTo(this.symbolWidth(), Math.round(this.size / 2));
|
|
ctx.lineTo(0, this.size);
|
|
ctx.lineTo(0, 0);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolStepForward = function (ctx, color) {
|
|
// draw a right-pointing triangle
|
|
// followed by a vertical bar
|
|
var w = this.symbolWidth(),
|
|
h = this.size;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 0);
|
|
ctx.lineTo(w * 0.75, Math.round(h / 2));
|
|
ctx.lineTo(0, h);
|
|
ctx.lineTo(0, 0);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
ctx.fillRect(
|
|
w * 0.75,
|
|
0,
|
|
w * 0.25,
|
|
h
|
|
);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolGears = function (ctx, color) {
|
|
// draw gears
|
|
var w = this.symbolWidth(),
|
|
r = w / 2,
|
|
spikes = 8,
|
|
off = 8,
|
|
shift = 10,
|
|
angle, turn, i;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
|
|
// draw the spiked outline
|
|
ctx.moveTo(w, r);
|
|
angle = 360 / spikes;
|
|
turn = angle * 0.5;
|
|
for (i = 0; i < spikes; i += 1) {
|
|
ctx.arc(
|
|
r,
|
|
r,
|
|
r,
|
|
radians(i * angle + turn),
|
|
radians(i * angle + off + turn)
|
|
);
|
|
ctx.arc(
|
|
r,
|
|
r,
|
|
r * 0.7,
|
|
radians(i * angle - shift + angle * 0.5 + turn),
|
|
radians(i * angle + shift + angle * 0.5 + turn)
|
|
);
|
|
ctx.arc(
|
|
r,
|
|
r,
|
|
r,
|
|
radians((i + 1) * angle - off + turn),
|
|
radians((i + 1) * angle + turn)
|
|
);
|
|
}
|
|
ctx.lineTo(w, r);
|
|
|
|
// draw the hole in the middle
|
|
ctx.arc(r, r, r * 0.3, radians(0), radians(360));
|
|
|
|
// fill
|
|
ctx.clip('evenodd');
|
|
ctx.fillRect(0, 0, w, w);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolGearBig = function (ctx, color) {
|
|
// draw a large gear
|
|
var w = this.symbolWidth(),
|
|
r = w / 2,
|
|
spikes = 10,
|
|
off = 7,
|
|
shift = 8,
|
|
angle, i;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
|
|
// draw the spiked outline
|
|
ctx.moveTo(w, r);
|
|
angle = 360 / spikes;
|
|
for (i = 0; i < spikes; i += 1) {
|
|
ctx.arc(
|
|
r,
|
|
r,
|
|
r,
|
|
radians(i * angle),
|
|
radians(i * angle + off)
|
|
);
|
|
ctx.arc(
|
|
r,
|
|
r,
|
|
r * 0.8,
|
|
radians(i * angle - shift + angle * 0.5),
|
|
radians(i * angle + shift + angle * 0.5)
|
|
);
|
|
ctx.arc(
|
|
r,
|
|
r,
|
|
r,
|
|
radians((i + 1) * angle - off),
|
|
radians((i + 1) * angle)
|
|
);
|
|
}
|
|
ctx.lineTo(w, r);
|
|
|
|
// draw the holes in the middle
|
|
ctx.arc(r, r, r * 0.6, radians(0), radians(360));
|
|
ctx.arc(r, r, r * 0.2, radians(0), radians(360));
|
|
|
|
// fill
|
|
ctx.clip('evenodd');
|
|
ctx.fillRect(0, 0, w, w);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolGearPartial = function (ctx, color) {
|
|
// draw gears
|
|
var w = this.symbolWidth(),
|
|
r = w * 0.75,
|
|
spikes = 8,
|
|
off = 8,
|
|
shift = 10,
|
|
angle, turn, i;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
|
|
// draw the spiked outline
|
|
ctx.moveTo(w, r);
|
|
angle = 360 / spikes;
|
|
turn = angle * 0.5;
|
|
for (i = 0; i < spikes; i += 1) {
|
|
ctx.arc(
|
|
r,
|
|
r,
|
|
r,
|
|
radians(i * angle + turn),
|
|
radians(i * angle + off + turn)
|
|
);
|
|
ctx.arc(
|
|
r,
|
|
r,
|
|
r * 0.7,
|
|
radians(i * angle - shift + angle * 0.5 + turn),
|
|
radians(i * angle + shift + angle * 0.5 + turn)
|
|
);
|
|
ctx.arc(
|
|
r,
|
|
r,
|
|
r,
|
|
radians((i + 1) * angle - off + turn),
|
|
radians((i + 1) * angle + turn)
|
|
);
|
|
}
|
|
ctx.lineTo(w, r);
|
|
|
|
// draw the hole in the middle
|
|
ctx.arc(r, r, r * 0.3, radians(0), radians(360));
|
|
|
|
// fill
|
|
ctx.clip('evenodd');
|
|
ctx.fillRect(0, 0, w, w);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolFile = function (ctx, color) {
|
|
// draw a page symbol
|
|
var height = this.size,
|
|
width = this.symbolWidth(),
|
|
w = Math.min(width, height) / 2;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 0);
|
|
ctx.lineTo(w, 0);
|
|
ctx.lineTo(w, w);
|
|
ctx.lineTo(width, w);
|
|
ctx.lineTo(width, height);
|
|
ctx.lineTo(0, height);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = color.darker(25).toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(w, 0);
|
|
ctx.lineTo(width, w);
|
|
ctx.lineTo(w, w);
|
|
ctx.lineTo(w, 0);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolFullScreen = function (ctx, color) {
|
|
// draw two arrows pointing diagonally outwards
|
|
var h = this.size,
|
|
width = this.symbolWidth(),
|
|
c = width / 2,
|
|
off = width / 20,
|
|
w = width / 2;
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = width / 5;
|
|
ctx.beginPath();
|
|
ctx.moveTo(c - off, c + off);
|
|
// ctx.lineTo(0, h);
|
|
ctx.lineTo(off * 2, h - off * 2);
|
|
ctx.stroke();
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = width / 5;
|
|
ctx.beginPath();
|
|
ctx.moveTo(c + off, c - off);
|
|
ctx.lineTo(h - off * 2, off * 2);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, h);
|
|
ctx.lineTo(0, h - w);
|
|
ctx.lineTo(w, h);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(h, 0);
|
|
ctx.lineTo(h - w, 0);
|
|
ctx.lineTo(h, w);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolGrow = function (ctx, color) {
|
|
|
|
var h = this.size,
|
|
width = this.symbolWidth(),
|
|
c = width / 2,
|
|
off = width / 20,
|
|
w = width / 3;
|
|
|
|
function arrows() {
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = width / 7;
|
|
ctx.beginPath();
|
|
ctx.moveTo(c - off * 3, c + off * 3);
|
|
ctx.lineTo(off * 2, h - off * 2);
|
|
ctx.stroke();
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = width / 7;
|
|
ctx.beginPath();
|
|
ctx.moveTo(c + off * 3 , c - off * 3);
|
|
ctx.lineTo(h - off * 2, off * 2);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, h);
|
|
ctx.lineTo(0, h - w);
|
|
ctx.lineTo(w, h);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(h, 0);
|
|
ctx.lineTo(h - w, 0);
|
|
ctx.lineTo(h, w);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
}
|
|
|
|
// draw four arrows pointing diagonally outwards
|
|
arrows();
|
|
ctx.translate(this.size, 0);
|
|
ctx.rotate(radians(90));
|
|
arrows();
|
|
};
|
|
|
|
|
|
SymbolMorph.prototype.renderSymbolNormalScreen = function (ctx, color) {
|
|
var h = this.size,
|
|
w = this.symbolWidth(),
|
|
c = w / 2,
|
|
off = w / 20;
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = w / 5;
|
|
ctx.beginPath();
|
|
ctx.moveTo(c - off * 3, c + off * 3);
|
|
ctx.lineTo(off, h - off);
|
|
ctx.stroke();
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = w / 5;
|
|
ctx.beginPath();
|
|
ctx.moveTo(c + off * 3, c - off * 3);
|
|
ctx.lineTo(h - off, off);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(c + off, c - off);
|
|
ctx.lineTo(w, c - off);
|
|
ctx.lineTo(c + off, 0);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(c - off, c + off);
|
|
ctx.lineTo(0, c + off);
|
|
ctx.lineTo(c - off, w);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolShrink = function (ctx, color) {
|
|
// draw 4 arrows pointing diagonally inwards
|
|
var h = this.size,
|
|
w = this.symbolWidth(),
|
|
c = w / 2,
|
|
off = w / 20;
|
|
|
|
function arrows() {
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = w / 8;
|
|
ctx.beginPath();
|
|
ctx.moveTo(c - off * 3, c + off * 3);
|
|
ctx.lineTo(off, h - off);
|
|
ctx.stroke();
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = w / 8;
|
|
ctx.beginPath();
|
|
ctx.moveTo(c + off * 3, c - off * 3);
|
|
ctx.lineTo(h - off, off);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(c + off * 2, c - off * 2);
|
|
ctx.lineTo(w - off, c - off * 2);
|
|
ctx.lineTo(c + off * 2, 0 + off);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(c - off * 2, c + off * 2);
|
|
ctx.lineTo(0 + off, c + off * 2);
|
|
ctx.lineTo(c - off * 2, w - off);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
}
|
|
|
|
arrows();
|
|
ctx.translate(this.size, 0);
|
|
ctx.rotate(radians(90));
|
|
arrows();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolSmallStage = function (ctx, color) {
|
|
// draw a stage toggling symbol
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
w2 = w / 2,
|
|
h2 = h / 2;
|
|
|
|
ctx.fillStyle = color.darker(50).toString();
|
|
ctx.fillRect(0, 0, w, h);
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.fillRect(w2, 0, w2, h2);
|
|
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolNormalStage = function (ctx, color) {
|
|
// draw a stage toggling symbol
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
w2 = w / 2,
|
|
h2 = h / 2;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.fillRect(0, 0, w, h);
|
|
|
|
ctx.fillStyle = color.darker(50).toString();
|
|
ctx.fillRect(w2, 0, w2, h2);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTurtle = function (ctx, color) {
|
|
// draw a LOGO turtle
|
|
var w = this.symbolWidth(),
|
|
h = this.size;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 0);
|
|
ctx.lineTo(w, h / 2);
|
|
ctx.lineTo(0, h);
|
|
ctx.lineTo(h / 2, h / 2);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTurtleOutline = function (ctx, color) {
|
|
// draw a LOGO turtle
|
|
var w = this.symbolWidth(),
|
|
h = this.size;
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 0);
|
|
ctx.lineTo(w, h / 2);
|
|
ctx.lineTo(0, h);
|
|
ctx.lineTo(h / 2, h / 2);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolPause = function (ctx, color) {
|
|
// draw two parallel rectangles
|
|
var w = this.symbolWidth() / 5,
|
|
h = this.size;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.fillRect(0, 0, w * 2, h);
|
|
ctx.fillRect(w * 3, 0, w * 2, h);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolFlag = function (ctx, color) {
|
|
// draw a flag
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
l = Math.max(w / 12, 1);
|
|
|
|
ctx.lineWidth = l;
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(l / 2, 0);
|
|
ctx.lineTo(l / 2, h);
|
|
ctx.stroke();
|
|
|
|
ctx.lineWidth = h / 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, h / 4);
|
|
ctx.bezierCurveTo(
|
|
w * 0.8,
|
|
h / 4,
|
|
w * 0.1,
|
|
h * 0.5,
|
|
w,
|
|
h * 0.5
|
|
);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolOctagon = function (ctx, color) {
|
|
// draw an octagon
|
|
var side = this.symbolWidth(),
|
|
vert = (side - (side * 0.383)) / 2;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(vert, 0);
|
|
ctx.lineTo(side - vert, 0);
|
|
ctx.lineTo(side, vert);
|
|
ctx.lineTo(side, side - vert);
|
|
ctx.lineTo(side - vert, side);
|
|
ctx.lineTo(vert, side);
|
|
ctx.lineTo(0, side - vert);
|
|
ctx.lineTo(0, vert);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolCloud = function (ctx, color) {
|
|
// draw a cloud
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
r1 = h * 2 / 5,
|
|
r2 = h / 4,
|
|
r3 = h * 3 / 10,
|
|
r4 = h / 5;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.arc(r2, h - r2, r2, radians(90), radians(259), false);
|
|
ctx.arc(w / 20 * 5, h / 9 * 4, r4, radians(165), radians(300), false);
|
|
ctx.arc(w / 20 * 11, r1, r1, radians(200), radians(357), false);
|
|
ctx.arc(w - r3, h - r3, r3, radians(269), radians(90), false);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolCloudGradient = function (ctx, color) {
|
|
// draw a cloud
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
gradient,
|
|
r1 = h * 2 / 5,
|
|
r2 = h / 4,
|
|
r3 = h * 3 / 10,
|
|
r4 = h / 5;
|
|
|
|
gradient = ctx.createRadialGradient(
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
w
|
|
);
|
|
gradient.addColorStop(0, color.lighter(25).toString());
|
|
gradient.addColorStop(1, color.darker(25).toString());
|
|
ctx.fillStyle = gradient;
|
|
ctx.beginPath();
|
|
ctx.arc(r2, h - r2, r2, radians(90), radians(259), false);
|
|
ctx.arc(w / 20 * 5, h / 9 * 4, r4, radians(165), radians(300), false);
|
|
ctx.arc(w / 20 * 11, r1, r1, radians(200), radians(357), false);
|
|
ctx.arc(w - r3, h - r3, r3, radians(269), radians(90), false);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolCloudOutline = function (ctx, color) {
|
|
// draw cloud
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
r1 = h * 2 / 5,
|
|
r2 = h / 4,
|
|
r3 = h * 3 / 10,
|
|
r4 = h / 5;
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.arc(r2 + 1, h - r2 - 1, r2, radians(90), radians(180), false);
|
|
ctx.arc(w / 20 * 5, h / 9 * 4, r4, radians(150), radians(300), false);
|
|
ctx.arc(w / 20 * 11, r1 + 1, r1, radians(210), radians(335), false);
|
|
ctx.arc(w - r3 - 1, h - r3 - 1, r3, radians(280), radians(90), false);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTurnRight = function (ctx, color) {
|
|
// draw a right-turning arrow
|
|
var w = this.symbolWidth(),
|
|
l = Math.max(w / 10, 1),
|
|
r = w / 2;
|
|
|
|
ctx.lineWidth = l;
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.arc(r, r * 2, r - l / 2, radians(0), radians(-90), false);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(w, r);
|
|
ctx.lineTo(r, 0);
|
|
ctx.lineTo(r, r * 2);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTurnLeft = function (ctx, color) {
|
|
// draw a left-turning arrow
|
|
var w = this.symbolWidth(),
|
|
l = Math.max(w / 10, 1),
|
|
r = w / 2;
|
|
|
|
ctx.lineWidth = l;
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.arc(r, r * 2, r - l / 2, radians(180), radians(-90), true);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, r);
|
|
ctx.lineTo(r, 0);
|
|
ctx.lineTo(r, r * 2);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTurnAround = function (ctx, color) {
|
|
// draw a right-around-turning arrow
|
|
var w = this.symbolWidth(),
|
|
l = Math.max(w / 10, 1),
|
|
r = w / 2;
|
|
|
|
ctx.lineWidth = l;
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.arc(r, r, r - l / 2, radians(-45), radians(225), false);
|
|
ctx.stroke();
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, r * 0.1);
|
|
ctx.lineTo(r * 0.8, 0);
|
|
ctx.lineTo(r * 0.7, r * 0.7);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolStorage = function (ctx, color) {
|
|
// draw a stack of three disks
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
r = h,
|
|
unit = h / 11;
|
|
|
|
function drawDisk(bottom) {
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.arc(w / 2, bottom - h, r, radians(60), radians(120), false);
|
|
ctx.lineTo(0, bottom - unit * 2);
|
|
ctx.arc(
|
|
w / 2,
|
|
bottom - h - unit * 2,
|
|
r,
|
|
radians(120),
|
|
radians(60),
|
|
true
|
|
);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = color.darker(25).toString();
|
|
ctx.beginPath();
|
|
ctx.arc(
|
|
w / 2,
|
|
bottom + unit * 6 + 1,
|
|
r,
|
|
radians(-120), // 60
|
|
radians(-60), // 120
|
|
false // true
|
|
);
|
|
ctx.stroke();
|
|
}
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
drawDisk(h);
|
|
drawDisk(h - unit * 3);
|
|
drawDisk(h - unit * 6);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolPoster = function (ctx, color) {
|
|
// draw a poster stand
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
bottom = h * 0.75,
|
|
edge = h / 5;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.strokeStyle = color.toString();
|
|
|
|
ctx.lineWidth = w / 15;
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(w / 2, h / 3);
|
|
ctx.lineTo(w / 6, h);
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(w / 2, h / 3);
|
|
ctx.lineTo(w / 2, h);
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(w / 2, h / 3);
|
|
ctx.lineTo(w * 5 / 6, h);
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 0);
|
|
ctx.lineTo(w, 0);
|
|
ctx.lineTo(w, bottom - edge);
|
|
ctx.lineTo(w - edge, bottom - edge);
|
|
ctx.lineTo(w - edge, bottom);
|
|
ctx.lineTo(0, bottom);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = color.darker(25).toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(w, bottom - edge);
|
|
ctx.lineTo(w - edge, bottom - edge);
|
|
ctx.lineTo(w - edge, bottom);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolFlash = function (ctx, color) {
|
|
// draw a lightning bolt
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
w3 = w / 3,
|
|
h3 = h / 3,
|
|
off = h3 / 3;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(w3, 0);
|
|
ctx.lineTo(0, h3);
|
|
ctx.lineTo(w3, h3);
|
|
ctx.lineTo(0, h3 * 2);
|
|
ctx.lineTo(w3, h3 * 2);
|
|
ctx.lineTo(0, h);
|
|
ctx.lineTo(w, h3 * 2 - off);
|
|
ctx.lineTo(w3 * 2, h3 * 2 - off);
|
|
ctx.lineTo(w, h3 - off);
|
|
ctx.lineTo(w3 * 2, h3 - off);
|
|
ctx.lineTo(w, 0);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolBrush = function (ctx, color) {
|
|
// draw a paintbrush
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
l = Math.max(w / 30, 0.5);
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(w / 8 * 3, h / 2);
|
|
ctx.quadraticCurveTo(0, h / 2, l, h - l);
|
|
ctx.quadraticCurveTo(w / 2, h, w / 2, h / 8 * 5);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.lineJoin = 'round';
|
|
ctx.lineCap = 'round';
|
|
ctx.strokeStyle = color.toString();
|
|
|
|
ctx.moveTo(w / 8 * 3, h / 2);
|
|
ctx.lineTo(w * 0.75, l);
|
|
ctx.quadraticCurveTo(w, 0, w - l, h * 0.25);
|
|
ctx.stroke();
|
|
|
|
ctx.moveTo(w / 2, h / 8 * 5);
|
|
ctx.lineTo(w - l, h * 0.25);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTick = function (ctx, color) {
|
|
// draw a check mark
|
|
var w = this.symbolWidth(),
|
|
h = this.size;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(w * 0.2, h * 0.5);
|
|
ctx.lineTo(w * 0.5, h);
|
|
ctx.lineTo(w * 0.8, h * 0.3);
|
|
ctx.lineTo(w, 0);
|
|
ctx.lineTo(w * 0.65, h * 0.2);
|
|
ctx.lineTo(w * 0.5, h * 0.65);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolCheckedBox = function (ctx, color) {
|
|
// draw a rectangle with a check mark
|
|
this.renderSymbolRectangle(ctx, color);
|
|
this.renderSymbolTick(ctx, color);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolRectangle = function (ctx, color) {
|
|
// draw a rectangle
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, l);
|
|
ctx.lineTo(w - l, l);
|
|
ctx.lineTo(w - l, h - l);
|
|
ctx.lineTo(l, h - l);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolRectangleSolid = function (ctx, color) {
|
|
// draw a solid rectangle
|
|
var w = this.symbolWidth(),
|
|
h = this.size;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, 0);
|
|
ctx.lineTo(w, 0);
|
|
ctx.lineTo(w, h);
|
|
ctx.lineTo(0, h);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolCircle = function (ctx, color) {
|
|
// draw a circle
|
|
var w = this.symbolWidth(),
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.arc(w / 2, w / 2, w / 2 - l, radians(0), radians(360), false);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolCircleSolid = function (ctx, color) {
|
|
// draw a solid circle
|
|
var w = this.symbolWidth();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.arc(w / 2, w / 2, w / 2, radians(0), radians(360), false);
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolLine = function (ctx, color) {
|
|
// draw a plus sign cross
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.lineCap = 'round';
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, l);
|
|
ctx.lineTo(w - l, h - l);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolCross = function (ctx, color) {
|
|
// draw a diagonal line
|
|
var w = this.symbolWidth(),
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.lineCap = 'round';
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, w / 2);
|
|
ctx.lineTo(w - l, w / 2);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.moveTo(w / 2, l);
|
|
ctx.lineTo(w / 2, w - l);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolCrosshairs = function (ctx, color) {
|
|
// draw a crosshairs
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
l = 0.5;
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, h / 2);
|
|
ctx.lineTo(w - l, h / 2);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.moveTo(w / 2, l);
|
|
ctx.lineTo(w / 2, h - l);
|
|
ctx.stroke();
|
|
ctx.beginPath();
|
|
ctx.moveTo(w / 2, h / 2);
|
|
ctx.arc(w / 2, w / 2, w / 3 - l, radians(0), radians(360), false);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolPaintbucket = function (ctx, color) {
|
|
// draw a paint bucket
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 5,
|
|
l = Math.max(w / 30, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(n * 2, n);
|
|
ctx.lineTo(n * 4, n * 3);
|
|
ctx.lineTo(n * 3, n * 4);
|
|
ctx.quadraticCurveTo(n * 2, h, n, n * 4);
|
|
ctx.quadraticCurveTo(0, n * 3, n, n * 2);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
|
|
ctx.lineWidth = l;
|
|
ctx.moveTo(n * 2, n * 2.5);
|
|
ctx.arc(n * 2, n * 2.5, l, radians(0), radians(360), false);
|
|
ctx.stroke();
|
|
|
|
ctx.moveTo(n * 2, n * 2.5);
|
|
ctx.lineTo(n * 2, n / 2 + l);
|
|
ctx.stroke();
|
|
|
|
ctx.arc(n * 1.5, n / 2 + l, n / 2, radians(0), radians(180), true);
|
|
ctx.stroke();
|
|
|
|
ctx.moveTo(n, n / 2 + l);
|
|
ctx.lineTo(n, n * 2);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(n * 3.5, n * 3.5);
|
|
ctx.quadraticCurveTo(w, n * 3.5, w - l, h);
|
|
ctx.lineTo(w, h);
|
|
ctx.quadraticCurveTo(w, n * 2, n * 2.5, n * 1.5);
|
|
ctx.lineTo(n * 4, n * 3);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolEraser = function (ctx, color) {
|
|
// draw an eraser
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 4,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(n * 3, l);
|
|
ctx.lineTo(l, n * 3);
|
|
ctx.quadraticCurveTo(n, h, n * 2, n * 3);
|
|
ctx.lineTo(w - l, n);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(n * 3, 0);
|
|
ctx.lineTo(n * 1.5, n * 1.5);
|
|
ctx.lineTo(n * 2.5, n * 2.5);
|
|
ctx.lineTo(w, n);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolPipette = function (ctx, color) {
|
|
// draw an eyedropper
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 4,
|
|
n2 = n / 2,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, h - l);
|
|
ctx.quadraticCurveTo(n2, h - n2, n2, h - n);
|
|
ctx.lineTo(n * 2, n * 1.5);
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, h - l);
|
|
ctx.quadraticCurveTo(n2, h - n2, n, h - n2);
|
|
ctx.lineTo(n * 2.5, n * 2);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.arc(n * 3, n, n - l, radians(0), radians(360), false);
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(n * 2, n);
|
|
ctx.lineTo(n * 3, n * 2);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolSpeechBubble = function (ctx, color) {
|
|
// draw a speech bubble
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 3,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(n, n * 2);
|
|
ctx.quadraticCurveTo(l, n * 2, l, n);
|
|
ctx.quadraticCurveTo(l, l, n, l);
|
|
ctx.lineTo(n * 2, l);
|
|
ctx.quadraticCurveTo(w - l, l, w - l, n);
|
|
ctx.quadraticCurveTo(w - l, n * 2, n * 2, n * 2);
|
|
ctx.lineTo(n / 2, h - l);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolSpeechBubbleOutline = function (
|
|
ctx,
|
|
color
|
|
) {
|
|
// draw a speech bubble
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 3,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(n, n * 2);
|
|
ctx.quadraticCurveTo(l, n * 2, l, n);
|
|
ctx.quadraticCurveTo(l, l, n, l);
|
|
ctx.lineTo(n * 2, l);
|
|
ctx.quadraticCurveTo(w - l, l, w - l, n);
|
|
ctx.quadraticCurveTo(w - l, n * 2, n * 2, n * 2);
|
|
ctx.lineTo(n / 2, h - l);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolLoop = function (ctx, aColor) {
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
w2 = w / 2,
|
|
w4 = w2 / 2,
|
|
h2 = h / 2,
|
|
l = Math.max(h / 10, 0.5);
|
|
|
|
ctx.lineWidth = l * 2;
|
|
ctx.strokeStyle = aColor.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, h - l);
|
|
ctx.lineTo(w2, h - l);
|
|
ctx.arc(w2, h2, h2 - l, radians(90), radians(0), true);
|
|
ctx.stroke();
|
|
ctx.fillStyle = aColor.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(w4 * 3 - l, 0);
|
|
ctx.lineTo(w2 - l, h2);
|
|
ctx.lineTo(w, h2);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTurnBack = function (ctx, aColor) {
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
w2 = w / 2,
|
|
h2 = h / 2,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.fillStyle = aColor.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(0, h2);
|
|
ctx.lineTo(w2, 0);
|
|
ctx.lineTo(w2, h);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
ctx.lineWidth = l * 3;
|
|
ctx.strokeStyle = aColor.toString();
|
|
ctx.beginPath();
|
|
ctx.arc(w2, h, h2, radians(0), radians(-90), true);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTurnForward = function (ctx, aColor) {
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
w2 = w / 2,
|
|
h2 = h / 2,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.fillStyle = aColor.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(w, h2);
|
|
ctx.lineTo(w2, 0);
|
|
ctx.lineTo(w2, h);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
ctx.lineWidth = l * 3;
|
|
ctx.strokeStyle = aColor.toString();
|
|
ctx.beginPath();
|
|
ctx.arc(w2, h, h2, radians(-180), radians(-90), false);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowUp = function (ctx, color) {
|
|
// draw an up arrow
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 2,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, n);
|
|
ctx.lineTo(n, l);
|
|
ctx.lineTo(w - l, n);
|
|
ctx.lineTo(w * 0.65, n);
|
|
ctx.lineTo(w * 0.65, h - l);
|
|
ctx.lineTo(w * 0.35, h - l);
|
|
ctx.lineTo(w * 0.35, n);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowUpOutline = function (ctx, color) {
|
|
// draw an up arrow
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 2,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, n);
|
|
ctx.lineTo(n, l);
|
|
ctx.lineTo(w - l, n);
|
|
ctx.lineTo(w * 0.65, n);
|
|
ctx.lineTo(w * 0.65, h - l);
|
|
ctx.lineTo(w * 0.35, h - l);
|
|
ctx.lineTo(w * 0.35, n);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowUpThin = function (ctx, color) {
|
|
// draw a thin up arrow
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 3,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(w - n, n);
|
|
ctx.lineTo(w / 2, l * 2);
|
|
ctx.lineTo(n, n);
|
|
ctx.moveTo(w / 2, l * 2);
|
|
ctx.lineTo(w / 2, h - l);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowUpDownThin = function (ctx, color) {
|
|
// draw a thin up-down arrow
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 3,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(w - n, n);
|
|
ctx.lineTo(w / 2, l * 2);
|
|
ctx.lineTo(n, n);
|
|
ctx.moveTo(w - n, h - n);
|
|
ctx.lineTo(w / 2, h - l * 2);
|
|
ctx.lineTo(n, h - n);
|
|
ctx.moveTo(w / 2, l * 2);
|
|
ctx.lineTo(w / 2, h - l * 2);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowDown = function (ctx, color) {
|
|
// draw a down arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(w, w);
|
|
ctx.rotate(radians(180));
|
|
this.renderSymbolArrowUp(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowDownOutline = function (ctx, color) {
|
|
// draw a down arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(w, w);
|
|
ctx.rotate(radians(180));
|
|
this.renderSymbolArrowUpOutline(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowDownThin = function (ctx, color) {
|
|
// draw a thin down arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(w, w);
|
|
ctx.rotate(radians(180));
|
|
this.renderSymbolArrowUpThin(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowLeft = function (ctx, color) {
|
|
// draw a left arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(0, w);
|
|
ctx.rotate(radians(-90));
|
|
this.renderSymbolArrowUp(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowLeftOutline = function (ctx, color) {
|
|
// draw a left arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(0, w);
|
|
ctx.rotate(radians(-90));
|
|
this.renderSymbolArrowUpOutline(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowLeftThin = function (ctx, color) {
|
|
// draw a thin left arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(0, w);
|
|
ctx.rotate(radians(-90));
|
|
this.renderSymbolArrowUpThin(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowLeftRightThin = function (ctx, color) {
|
|
// draw a thin left-right arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(0, w);
|
|
ctx.rotate(radians(-90));
|
|
this.renderSymbolArrowUpDownThin(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowRight = function (ctx, color) {
|
|
// draw a right arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(w, 0);
|
|
ctx.rotate(radians(90));
|
|
this.renderSymbolArrowUp(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowRightOutline = function (ctx, color) {
|
|
// draw a right arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(w, 0);
|
|
ctx.rotate(radians(90));
|
|
this.renderSymbolArrowUpOutline(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolArrowRightThin = function (ctx, color) {
|
|
// draw a thin right arrow
|
|
var w = this.symbolWidth();
|
|
ctx.save();
|
|
ctx.translate(w, 0);
|
|
ctx.rotate(radians(90));
|
|
this.renderSymbolArrowUpThin(ctx, color);
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolRobot = function (ctx, color) {
|
|
// draw a humanoid robot
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
n = w / 6,
|
|
n2 = n / 2,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.fillStyle = color.toString();
|
|
//ctx.lineWidth = l * 2;
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(n + l, n);
|
|
ctx.lineTo(n * 2, n);
|
|
ctx.lineTo(n * 2.5, n * 1.5);
|
|
ctx.lineTo(n * 3.5, n * 1.5);
|
|
ctx.lineTo(n * 4, n);
|
|
ctx.lineTo(n * 5 - l, n);
|
|
ctx.lineTo(n * 4, n * 3);
|
|
ctx.lineTo(n * 4, n * 4 - l);
|
|
ctx.lineTo(n * 2, n * 4 - l);
|
|
ctx.lineTo(n * 2, n * 3);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(n * 2.75, n + l);
|
|
ctx.lineTo(n * 2.4, n);
|
|
ctx.lineTo(n * 2.2, 0);
|
|
ctx.lineTo(n * 3.8, 0);
|
|
ctx.lineTo(n * 3.6, n);
|
|
ctx.lineTo(n * 3.25, n + l);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(n * 2.5, n * 4);
|
|
ctx.lineTo(n, n * 4);
|
|
ctx.lineTo(n2 + l, h);
|
|
ctx.lineTo(n * 2, h);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(n * 3.5, n * 4);
|
|
ctx.lineTo(n * 5, n * 4);
|
|
ctx.lineTo(w - (n2 + l), h);
|
|
ctx.lineTo(n * 4, h);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(n, n);
|
|
ctx.lineTo(l, n * 1.5);
|
|
ctx.lineTo(l, n * 3.25);
|
|
ctx.lineTo(n * 1.5, n * 3.5);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(n * 5, n);
|
|
ctx.lineTo(w - l, n * 1.5);
|
|
ctx.lineTo(w - l, n * 3.25);
|
|
ctx.lineTo(n * 4.5, n * 3.5);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolMagnifyingGlass = function (ctx, color) {
|
|
// draw a magnifying glass
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
gradient,
|
|
r = w * 0.3,
|
|
x = w * 2 / 3 - Math.sqrt(r),
|
|
y = h / 3 + Math.sqrt(r),
|
|
l = Math.max(w / 5, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
|
|
gradient = ctx.createRadialGradient(
|
|
x,
|
|
y,
|
|
0,
|
|
x + r,
|
|
y + r,
|
|
w
|
|
);
|
|
|
|
gradient.addColorStop(0, color.inverted().lighter(50).toString());
|
|
gradient.addColorStop(1, color.inverted().darker(25).toString());
|
|
ctx.fillStyle = gradient;
|
|
ctx.beginPath();
|
|
ctx.arc(x, y, r, radians(0), radians(360), false);
|
|
ctx.fill();
|
|
|
|
ctx.lineWidth = l / 2;
|
|
ctx.beginPath();
|
|
ctx.arc(x, y, r, radians(0), radians(360), false);
|
|
ctx.stroke();
|
|
|
|
ctx.lineWidth = l;
|
|
ctx.beginPath();
|
|
ctx.moveTo(l / 2, h - l / 2);
|
|
ctx.lineTo(x - Math.sqrt(r + l), y + Math.sqrt(r + l));
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolMagnifierOutline = function (ctx, color) {
|
|
// draw a magnifying glass
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
r = w * 0.3,
|
|
x = w * 2 / 3 - Math.sqrt(r),
|
|
y = h / 3 + Math.sqrt(r),
|
|
l = Math.max(w / 5, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
|
|
ctx.lineWidth = l * 0.5;
|
|
ctx.beginPath();
|
|
ctx.arc(x, y, r, radians(0), radians(360), false);
|
|
ctx.stroke();
|
|
|
|
ctx.lineWidth = l;
|
|
ctx.beginPath();
|
|
ctx.moveTo(l / 2, h - l / 2);
|
|
ctx.lineTo(x - Math.sqrt(r + l), y + Math.sqrt(r + l));
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
};
|
|
|
|
|
|
SymbolMorph.prototype.renderSymbolSelection = function (ctx, color) {
|
|
// draw a filled arrow and a dashed rectangle
|
|
var w = this.symbolWidth(),
|
|
h = this.size;
|
|
|
|
ctx.save();
|
|
ctx.setLineDash([3]);
|
|
this.renderSymbolRectangle(ctx, color);
|
|
ctx.restore();
|
|
|
|
ctx.save();
|
|
ctx.fillStyle = color.toString();
|
|
ctx.translate(0.7 * w, 0.4 * h);
|
|
ctx.scale(0.5, 0.5);
|
|
ctx.rotate(radians(135));
|
|
this.renderSymbolArrowDownOutline(ctx, color);
|
|
ctx.fill();
|
|
ctx.restore();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolOctagonOutline = function (ctx, color) {
|
|
// draw an octagon
|
|
var side = this.symbolWidth(),
|
|
vert = (side - (side * 0.383)) / 2,
|
|
l = Math.max(side / 20, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(vert, l);
|
|
ctx.lineTo(side - vert, l);
|
|
ctx.lineTo(side - l, vert);
|
|
ctx.lineTo(side - l, side - vert);
|
|
ctx.lineTo(side - vert, side - l);
|
|
ctx.lineTo(vert, side - l);
|
|
ctx.lineTo(l, side - vert);
|
|
ctx.lineTo(l, vert);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolClosedBrushPath =
|
|
SymbolMorph.prototype.renderSymbolCloudOutline;
|
|
|
|
SymbolMorph.prototype.renderSymbolNotes = function (ctx, color) {
|
|
// draw two musical notes
|
|
var size = this.symbolWidth(),
|
|
r = size / 6,
|
|
l = Math.max(r / 3, 1);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.fillStyle = color.toString();
|
|
|
|
ctx.beginPath();
|
|
ctx.arc(r, size - r, r, radians(0), radians(360), false);
|
|
ctx.fill();
|
|
ctx.beginPath();
|
|
ctx.arc(size - r, size - (r * 2), r, radians(0), radians(360), false);
|
|
ctx.fill();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(r * 2 - l, r);
|
|
ctx.lineTo(size, 0);
|
|
ctx.lineTo(size, r);
|
|
ctx.lineTo(r * 2 - l, r * 2);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.lineWidth = l;
|
|
ctx.beginPath();
|
|
ctx.moveTo(r * 2 - (l / 2), size - r);
|
|
ctx.lineTo(r * 2 - (l / 2), r + l);
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(size - (l / 2), size - (r * 2));
|
|
ctx.lineTo(size - (l / 2), l);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolCamera = function (ctx, color) {
|
|
// draw a camera
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
r = w * 0.16,
|
|
l = Math.max(w / 20, 0.5);
|
|
|
|
ctx.lineWidth = l * 2;
|
|
|
|
// camera body
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, h * 5 / 6);
|
|
ctx.lineTo(w - l, h * 5 / 6);
|
|
ctx.lineTo(w - l, h / 4);
|
|
ctx.lineTo(w * 3 / 4 , h / 4);
|
|
ctx.lineTo(w * 5 / 8 , l);
|
|
ctx.lineTo(w * 3 / 8 , l);
|
|
ctx.lineTo(w / 4 , h / 4);
|
|
ctx.lineTo(l , h / 4);
|
|
ctx.lineTo(l, h * 5 / 6);
|
|
|
|
// camera lens
|
|
ctx.arc(w / 2, h / 2, r, radians(0), radians(360), false);
|
|
|
|
ctx.clip();
|
|
ctx.fillRect(0, 0, w, h);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolLocation = function (ctx, color) {
|
|
// draw a map pin
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
r = w / 2;
|
|
|
|
// pin
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
|
|
ctx.moveTo(0, r);
|
|
ctx.arc(r, r, r, radians(-180), radians(0), false);
|
|
ctx.lineTo(r, h);
|
|
ctx.lineTo(0, r);
|
|
|
|
// hole
|
|
ctx.arc(r, r, r * 0.5, radians(0), radians(360), false);
|
|
|
|
ctx.clip('evenodd');
|
|
ctx.fillRect(0, 0, w, h);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolFootprints = function (ctx, color) {
|
|
// draw a pair of (shoe) footprints
|
|
var w = this.symbolWidth(),
|
|
u = w / 10,
|
|
r = u * 1.5;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
|
|
// left shoe
|
|
// tip
|
|
ctx.beginPath();
|
|
ctx.arc(r, r, r, radians(-200), radians(0), false);
|
|
ctx.lineTo(r * 2, u * 5.5);
|
|
ctx.lineTo(u, u * 6);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
// heel
|
|
ctx.beginPath();
|
|
ctx.arc(u * 2.25, u * 6.75, u , radians(-40), radians(-170), false);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
// right shoe
|
|
// tip
|
|
ctx.beginPath();
|
|
ctx.arc(w - r, u * 4.5, r, radians(-180), radians(20), false);
|
|
ctx.lineTo(w - u, u * 8.5);
|
|
ctx.lineTo(w - (r * 2), u * 8);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
// heel
|
|
ctx.beginPath();
|
|
ctx.arc(w - (u * 2.25), u * 9, u, radians(0), radians(-150), false);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolKeyboard = function (ctx, color) {
|
|
// draw a typing keyboard
|
|
var h = this.size,
|
|
u = h / 10,
|
|
k = h / 5,
|
|
row, col;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
for (row = 0; row < 2; row += 1) {
|
|
for (col = 0; col < 5; col += 1) {
|
|
ctx.fillRect(
|
|
((u + k) * col) + u,
|
|
((u + k) * row) + u,
|
|
k,
|
|
k
|
|
);
|
|
}
|
|
}
|
|
ctx.fillRect(u * 4, u * 7, k * 4, k);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolKeyboardFilled = function (ctx, color) {
|
|
// draw a typing keyboard
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
u = h / 10,
|
|
k = h / 5,
|
|
row, col;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.rect(0, 0, w, h);
|
|
for (row = 0; row < 2; row += 1) {
|
|
for (col = 0; col < 5; col += 1) {
|
|
ctx.rect(
|
|
((u + k) * col) + u,
|
|
((u + k) * row) + u,
|
|
k,
|
|
k
|
|
);
|
|
}
|
|
}
|
|
ctx.rect(u * 4, u * 7, k * 4, k);
|
|
|
|
ctx.clip('evenodd');
|
|
ctx.fillRect(0, 0, w, h);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolGlobeBig = function (ctx, color) {
|
|
this.renderSymbolGlobe(ctx, color, true);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolGlobe = function (ctx, color, detailed) {
|
|
// draw a stylized globe
|
|
var w = this.symbolWidth(),
|
|
l = Math.max(w / 30, 0.5);
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = l * 2;
|
|
|
|
ctx.beginPath();
|
|
ctx.arc(w / 2, w / 2, w / 2 - l, radians(0), radians(360), false);
|
|
ctx.stroke();
|
|
|
|
if (detailed) {
|
|
ctx.moveTo(l * 3, w * 0.3);
|
|
ctx.lineTo(w - l * 3, w * 0.3);
|
|
ctx.stroke();
|
|
ctx.moveTo(l * 3, w * 0.7);
|
|
ctx.lineTo(w - l * 3, w * 0.7);
|
|
ctx.stroke();
|
|
}
|
|
|
|
// single line version, looks better when small:
|
|
ctx.beginPath();
|
|
ctx.moveTo(l, w / 2);
|
|
ctx.lineTo(w - l, w / 2);
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(w / 2, l / 2);
|
|
ctx.arcTo(0, w / 2, w / 2, w, w * 0.75);
|
|
ctx.stroke();
|
|
|
|
ctx.beginPath();
|
|
ctx.moveTo(w / 2, l / 2);
|
|
ctx.arcTo(w, w / 2, w / 2, w, w * 0.75);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolList = function (ctx, color) {
|
|
// draw a stylized list
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
padding = h / 10,
|
|
item = h / 5,
|
|
row;
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.rect(0, 0, w, h);
|
|
for (row = 0; row < 4; row += 1) {
|
|
ctx.rect(
|
|
padding,
|
|
((padding + item) * row) + padding,
|
|
w - item,
|
|
item
|
|
);
|
|
}
|
|
ctx.clip('evenodd');
|
|
ctx.fillRect(0, 0, w, h);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolFlipHorizontal = function (ctx, color) {
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
c = w / 2,
|
|
off = w / 15;
|
|
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = w / 15;
|
|
ctx.beginPath();
|
|
ctx.moveTo(0 + off, h - off / 2);
|
|
ctx.lineTo(c - off * 1.2, h - off / 2);
|
|
ctx.lineTo(c - off * 1.2, off * 2);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = color.toString();
|
|
ctx.lineWidth = w / 15;
|
|
ctx.beginPath();
|
|
ctx.moveTo(w - off, h - off / 2);
|
|
ctx.lineTo(c + off * 1.2, h - off / 2);
|
|
ctx.lineTo(c + off * 1.2, off * 2);
|
|
ctx.closePath();
|
|
ctx.stroke();
|
|
ctx.fill();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolFlipVertical = function (ctx, color) {
|
|
ctx.translate(0, this.size);
|
|
ctx.rotate(radians(-90));
|
|
this.renderSymbolFlipHorizontal(ctx, color);
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTrash = function (ctx, color) {
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
step = w / 10;
|
|
|
|
function stripe(x) {
|
|
var half = step / 2;
|
|
ctx.moveTo(x - half, step * 4);
|
|
ctx.arc(x, step * 4, half, radians(180), radians(0));
|
|
ctx.lineTo(x + half, step * 8.5);
|
|
ctx.arc(x, step * 8.5, half, radians(0), radians(180));
|
|
ctx.lineTo(x - half, step * 4);
|
|
}
|
|
|
|
// body of the can
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(step, step * 2.5);
|
|
ctx.lineTo(step * 1.5, step * 9.5);
|
|
ctx.lineTo(step * 2.5, h);
|
|
ctx.lineTo(step * 7.5, h);
|
|
ctx.lineTo(step * 8.5, step * 9.5);
|
|
ctx.lineTo(step * 9, step * 2.5);
|
|
ctx.lineTo(step, step * 2.5);
|
|
|
|
// vertical stripes
|
|
stripe(w * 0.3);
|
|
stripe(w * 0.5);
|
|
stripe(w * 0.7);
|
|
|
|
ctx.save();
|
|
ctx.clip();
|
|
ctx.fillRect(0, 0, w, h);
|
|
ctx.restore();
|
|
|
|
// the lid
|
|
ctx.lineWidth = step;
|
|
ctx.lineJoin = 'round';
|
|
ctx.strokeStyle = color.toString();
|
|
ctx.lineWidth = step;
|
|
ctx.beginPath();
|
|
ctx.moveTo(step / 2, step * 1.5);
|
|
ctx.lineTo(step * 9.5, step * 1.5);
|
|
ctx.stroke();
|
|
|
|
// the handle on the lid
|
|
ctx.lineWidth = step / 2;
|
|
ctx.beginPath();
|
|
ctx.moveTo(step * 3, step * 1.5);
|
|
ctx.lineTo(step * 4, step * 0.25);
|
|
ctx.lineTo(step * 6, step * 0.25);
|
|
ctx.lineTo(step * 7, step * 1.5);
|
|
ctx.stroke();
|
|
};
|
|
|
|
SymbolMorph.prototype.renderSymbolTrashFull = function (ctx, color) {
|
|
var w = this.symbolWidth(),
|
|
h = this.size,
|
|
step = w / 10;
|
|
|
|
function stripe(x) {
|
|
var half = step / 2;
|
|
ctx.moveTo(x - half, step * 5.5);
|
|
ctx.arc(x, step * 5.5, half, radians(180), radians(0));
|
|
ctx.lineTo(x + half, step * 8.5);
|
|
ctx.arc(x, step * 8.5, half, radians(0), radians(180));
|
|
ctx.lineTo(x - half, step * 5.5);
|
|
}
|
|
|
|
// body of the can
|
|
ctx.fillStyle = color.toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(step, step * 4);
|
|
ctx.lineTo(step * 1.5, step * 9.5);
|
|
ctx.lineTo(step * 2.5, h);
|
|
ctx.lineTo(step * 7.5, h);
|
|
ctx.lineTo(step * 8.5, step * 9.5);
|
|
ctx.lineTo(step * 9, step * 4);
|
|
ctx.lineTo(step, step * 4);
|
|
|
|
// vertical stripes
|
|
stripe(w * 0.3);
|
|
stripe(w * 0.5);
|
|
stripe(w * 0.7);
|
|
|
|
ctx.save();
|
|
ctx.clip();
|
|
ctx.fillRect(0, 0, w, h);
|
|
ctx.restore();
|
|
|
|
// document
|
|
ctx.beginPath();
|
|
ctx.moveTo(step * 2, 0);
|
|
ctx.lineTo(step * 6, 0);
|
|
ctx.lineTo(step * 8, step * 2);
|
|
ctx.lineTo(step * 8, step * 3.5);
|
|
ctx.lineTo(step * 2, step * 3.5);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = color.darker(25).toString();
|
|
ctx.beginPath();
|
|
ctx.moveTo(step * 6, 0);
|
|
ctx.lineTo(step * 8, step * 2);
|
|
ctx.lineTo(step * 6, step * 2);
|
|
ctx.closePath();
|
|
ctx.fill();
|
|
};
|
|
|
|
/*
|
|
// register examples with the World demo menu
|
|
// comment out to shave off a millisecond loading speed ;-)
|
|
|
|
(function () {
|
|
var bright = new Color(240, 240, 240),
|
|
dark = new Color(20, 20, 20),
|
|
offset = new Point(-1, -1);
|
|
|
|
SymbolMorph.prototype.addToDemoMenu([
|
|
'Symbols',
|
|
SymbolMorph.prototype.names.map(sym => [
|
|
new SymbolMorph(
|
|
sym,
|
|
30,
|
|
bright,
|
|
offset,
|
|
dark
|
|
),
|
|
sym
|
|
])
|
|
]);
|
|
})();
|
|
*/
|