Recovering files from a backup

This commit is contained in:
Josh Sherman 2018-05-26 16:36:06 -05:00
commit 5ecc8c83b1
No known key found for this signature in database
GPG key ID: 55B058A80530EF22
49 changed files with 5236 additions and 0 deletions

9
README Normal file
View file

@ -0,0 +1,9 @@
DrawBox is a jQuery plug-in that allows you to create a very simple canvas for drawing.
The plug-in was originally conceived and designed to collect signatures via an iPad as well as the web. The plug-in has started to grow iand now includes a color selection option.
The raw SVG data for the drawing is stored in a hidden input element which is named %ID%-data, where %ID% is the ID of the canvas element that DrawBox was attached.
If you're unfortunate enough to have to support this plug-in in Internet Explorer, please use explorercanvas (included in the excanvas_r3 directory) http://code.google.com/p/explorercanvas/
Should you have any issues, or feedback, please contact me.

44
example.html Normal file
View file

@ -0,0 +1,44 @@
<!DOCTYPE html>
<html>
<head>
<title>jQuery DrawBox Example</title>
<style>
html { font-family: "Lucida Sans", "Lucida Grande", "Lucida Sans Unicode", sans-serif; background: #eee}
h1 { text-shadow: 1px 2px 5px #000; color: #fff }
canvas { background: #fff; border: 1px solid #999; -moz-border-radius: 10px; -webkit-border-radius: 10px }
a { color: #666; text-decoration: none }
a:hover { text-decoration: underline; color: #000 }
</style>
<!--[if IE]><script type="text/javascript" src="excanvas_r3/excanvas.compiled.js"></script><![endif]-->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
<script type="text/javascript" src="jquery.drawbox.js"></script>
<script type="text/javascript">
$(document).ready(function()
{
$('#drawbox').drawbox({caption:'This is a caption',lineWidth:3,lineCap:'round',lineJoin:'round',colorSelector:true});
$('#view-output').click(function()
{
var svgOutput = window.open('data:image/svg+xml,' + $('#drawbox-data').val());
svgOutput.document.close();
return false;
});
});
</script>
</head>
<body>
<h1>jQuery DrawBox Example</h1>
Click and drag your mouse or touch and move your finger in the box below
<br /><br />
<canvas id="drawbox" width="600" height="200">
<p>Your browser does not support &lt;canvas&gt;</p>
</canvas>
<br />
<a href="#" id="view-output">View Rendered SVG Output</a>
<br /><br />
<a href="http://github.com/crowdsavings/drawbox">github.com</a> |
<a href="http://plugins.jquery.com/project/drawbox">plugins.jquery.com</a>
</body>
</html>

10
excanvas_r3/AUTHORS Normal file
View file

@ -0,0 +1,10 @@
ExplorerCanvas
Google Open Source:
<http://code.google.com>
<opensource@google.com>
Developers:
Emil A Eklund <emil@eae.net>
Erik Arvidsson <erik@eae.net>
Glen Murphy <glen@glenmurphy.com>

202
excanvas_r3/COPYING Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

22
excanvas_r3/README Normal file
View file

@ -0,0 +1,22 @@
ExplorerCanvas
Copyright 2006 Google Inc.
-------------------------------------------------------------------------------
DESCRIPTION
Firefox, Safari and Opera 9 support the canvas tag to allow 2D command-based
drawing operations. ExplorerCanvas brings the same functionality to Internet
Explorer; web developers only need to include a single script tag in their
existing canvas webpages to enable this support.
-------------------------------------------------------------------------------
INSTALLATION
Include the ExplorerCanvas tag in the same directory as your HTML files, and
add the following code to your page, preferably in the <head> tag.
<!--[if IE]><script type="text/javascript" src="excanvas.js"></script><![endif]-->
If you run into trouble, please look at the included example code to see how
to best implement this

View file

@ -0,0 +1,29 @@
K 25
svn:wc:ra_dav:version-url
V 33
/svn/!svn/ver/47/tags/m3/examples
END
example1.html
K 25
svn:wc:ra_dav:version-url
V 47
/svn/!svn/ver/47/tags/m3/examples/example1.html
END
example2.html
K 25
svn:wc:ra_dav:version-url
V 47
/svn/!svn/ver/47/tags/m3/examples/example2.html
END
example3.html
K 25
svn:wc:ra_dav:version-url
V 47
/svn/!svn/ver/47/tags/m3/examples/example3.html
END
ff.jpg
K 25
svn:wc:ra_dav:version-url
V 40
/svn/!svn/ver/47/tags/m3/examples/ff.jpg
END

164
excanvas_r3/examples/.svn/entries Executable file
View file

@ -0,0 +1,164 @@
9
dir
48
https://explorercanvas.googlecode.com/svn/tags/m3/examples
https://explorercanvas.googlecode.com/svn
2009-03-03T04:08:38.771266Z
45
erik.arvidsson
svn:special svn:externals svn:needs-lock
fd59bba8-8519-0410-9389-e36bf2bdbbd6
example1.html
file
2009-03-22T18:57:18.447171Z
5e04009261a9176e95be3792bfe86132
2006-03-27T23:08:48.900864Z
2
frenzon
2280
example2.html
file
2009-03-22T18:57:18.448148Z
559dd246853d231c696c027b8ad5d432
2006-03-27T23:08:48.900864Z
2
frenzon
12507
example3.html
file
2009-03-22T18:57:18.450101Z
9bcfd5226573fad992e2bcaa0a12db2e
2006-03-27T23:08:48.900864Z
2
frenzon
7040
ff.jpg
file
2009-03-22T18:57:18.453031Z
8aeeb76823f8f736e9cae115fd0353b7
2006-03-27T23:08:48.900864Z
2
frenzon
has-props
25286

View file

@ -0,0 +1 @@
9

View file

@ -0,0 +1,5 @@
K 13
svn:mime-type
V 24
application/octet-stream
END

View file

@ -0,0 +1,93 @@
<!--
Copyright 2006 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<title>ExplorerCanvas Example 1</title>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script type="text/javascript">
var canvas, ctx;
var particles = [];
var NUM_PARTICLES = 20;
function Particle() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.xvel = Math.random() * 5 - 2.5;
this.yvel = Math.random() * 5 - 2.5;
}
Particle.prototype.update = function() {
this.x += this.xvel;
this.y += this.yvel;
this.yvel += 0.1;
if (this.x > canvas.width || this.x < 0) {
this.xvel = -this.xvel;
}
if (this.y > canvas.height || this.y < 0) {
this.yvel = -this.yvel;
}
}
function loop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = 0; i < NUM_PARTICLES; i++) {
particles[i].update();
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[i].x - particles[i].xvel,
particles[i].y - particles[i].yvel);
ctx.stroke();
ctx.closePath();
}
setTimeout(loop, 10);
}
function load() {
canvas = document.getElementById("cv");
ctx = canvas.getContext("2d");
for(var i = 0; i < NUM_PARTICLES; i++) {
particles[i] = new Particle();
}
ctx.lineWidth = "2";
ctx.strokeStyle = "rgb(255, 255, 255)";
loop();
}
</script>
<style>
body {
background-color:black;
margin:50px;
text-align:center;
}
canvas {
border:1px solid #444;
}
</style>
</head>
<body onload="load();">
<canvas id="cv" width="400" height="300"></canvas>
</body>
</html>

View file

@ -0,0 +1,513 @@
<!--
Copyright 2006 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<title>ExplorerCanvas Example 1</title>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script type="text/javascript">
/* -------------------------------------------------------------------- */
var canvas, ctx;
var canvasWidth, halfCanvasWidth;
var canvasHeight, halfCanvasHeight;
var space; // 3D Engine
var scene; // 3D Scene
/* -------------------------------------------------------------------- */
/**
* Space is a simple 3D system.
*
* Y+ = up
* Z+ = into screen
* X+ = right
*/
function Space() {
this.m = this.createMatrixIdentity();
this.mStack = [];
}
Space.prototype.createMatrixIdentity = function() {
return [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
];
}
/**
* Multiplies two 4x4 matricies together.
*/
Space.prototype.matrixMultiply = function(m1, m2) {
var result = this.createMatrixIdentity();
var width = m1[0].length;
var height = m1.length;
if (width != m2.length) {
// error
}
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
var sum = 0;
for (var z = 0; z < width; z++) {
sum += m1[y][z] * m2[z][x];
}
result[y][x] = sum;
}
}
return result;
}
/**
* Transforms a coordinate using the current transformation
* matrix, then flattens it using the projection matrix.
*/
Space.prototype.flatten = function(point) {
var p = [[point.x, point.y, point.z, 1]];
var pm = this.matrixMultiply(p, this.m);
point.tx = pm[0][0];
point.ty = pm[0][1];
point.tz = pm[0][2];
// lazy projection
point.fx = halfCanvasWidth + (canvasWidth * point.tx / point.tz);
point.fy = halfCanvasHeight -(canvasWidth * point.ty / point.tz);
}
/**
* Translate (move) the current transformation matrix
*/
Space.prototype.translate = function(x, y, z) {
var m = [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[x, y, z, 1]
];
this.m = this.matrixMultiply(m, this.m);
}
/**
* Rotate the current transformation matrix. Rotations are
* world-oriented, and occur in y,x,z order.
*/
Space.prototype.rotate = function(x, y, z) {
if (y) {
var cosY = Math.cos(y);
var sinY = Math.sin(y);
var rotY = [
[cosY, 0, sinY, 0],
[0, 1, 0, 0],
[-sinY, 0, cosY, 0],
[0, 0, 0, 1]
];
this.m = this.matrixMultiply(this.m, rotY);
}
if (x) {
var cosX = Math.cos(x);
var sinX = Math.sin(x);
var rotX = [
[1, 0, 0, 0],
[0, cosX, -sinX, 0],
[0, sinX, cosX,0],
[0, 0, 0, 1]
];
this.m = this.matrixMultiply(this.m, rotX);
}
if (z) {
var cosZ = Math.cos(z);
var sinZ = Math.sin(z);
var rotZ = [
[cosZ, -sinZ, 0, 0],
[sinZ, cosZ, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
];
this.m = this.matrixMultiply(this.m, rotZ);
}
}
/**
* Pushes the current transformation onto the stack
*/
Space.prototype.push = function() {
this.mStack.push(this.m);
this.m = [
[this.m[0][0], this.m[0][1], this.m[0][2], this.m[0][3]],
[this.m[1][0], this.m[1][1], this.m[1][2], this.m[1][3]],
[this.m[2][0], this.m[2][1], this.m[2][2], this.m[2][3]],
[this.m[3][0], this.m[3][1], this.m[3][2], this.m[3][3]]
];
}
/**
* Pops the end off the transformation stack
*/
Space.prototype.pop = function() {
this.m = this.mStack.pop();
}
/* -------------------------------------------------------------------- */
/**
* A 3d coordinate
*/
function Point(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
// Relative to camera coordinates
this.tx;
this.ty;
this.tz;
// Flattened coordinates
this.fx;
this.fy;
}
/**
* A Shape is made up of polygons
*/
function Shape() {
this.points = [];
this.polygons = [];
}
/**
* Draws the shape
*/
Shape.prototype.draw = function(drawlist) {
for (var i = 0; i< this.points.length; i++) {
space.flatten(this.points[i]);
}
for (var i = 0; i< this.polygons.length; i++) {
var poly = this.polygons[i]; // convenience
space.flatten(poly.origin);
// lazy backface culling
if (poly.normal && this.backface) {
space.flatten(poly.normal);
var originDist = Math.pow(poly.origin.tx, 2)
+ Math.pow(poly.origin.ty, 2)
+ Math.pow(poly.origin.tz, 2);
var normalDist = Math.pow(poly.normal.tx, 2)
+ Math.pow(poly.normal.ty, 2)
+ Math.pow(poly.normal.tz, 2);
if(originDist > normalDist) {
drawlist.push(poly);
}
} else {
drawlist.push(poly);
}
}
}
/**
* A polygon is a connection of points in the shape object. You
* should probably try to make them coplanar.
*/
function Polygon(points, normal, backface, type, color) {
this.points = points;
this.origin = new Point(0, 0, 0);
for(var i = 0; i < this.points.length; i++) {
this.origin.x += this.points[i].x;
this.origin.y += this.points[i].y;
this.origin.z += this.points[i].z;
}
this.origin.x /= this.points.length;
this.origin.y /= this.points.length;
this.origin.z /= this.points.length;
if (normal) {
this.normal = new Point(this.origin.x + normal.x,
this.origin.y + normal.y,
this.origin.z + normal.z);
} else {
this.normal = null;
}
this.backface = backface;
this.type = type;
this.color = color;
}
Polygon.SOLID = 0;
Polygon.WIRE = 1;
/**
* Draws the polygon. Assumes that the points have already been
* flattened.
*/
Polygon.prototype.draw = function() {
ctx.beginPath();
ctx.moveTo(this.points[0].fx, this.points[0].fy);
for(var i = 0; i < this.points.length; i++) {
ctx.lineTo(this.points[i].fx, this.points[i].fy);
}
ctx.closePath();
var color = this.color;
/*
// Do lighting here
lightvector = Math.abs(this.normal.x + this.normal.y);
if(lightvector > 1) {
lightvector = 1;
}
color[0] = (color[0] * lightvector).toString();
color[1] = (color[1] * lightvector).toString();
color[2] = (color[2] * lightvector).toString();
*/
if (color.length > 3) {
var style = ["rgba(",
color[0], ",",
color[1], ",",
color[2], ",",
color[3], ")"].join("");
} else {
var style = ["rgb(",
color[0], ",",
color[1], ",",
color[2], ")"].join("");
}
if (this.type == Polygon.SOLID) {
ctx.fillStyle = style;
ctx.fill();
} else if (this.type == Polygon.WIRE) {
ctx.strokeStyle = style;
ctx.stroke();
}
}
/* -------------------------------------------------------------------- */
/**
* Scene describes the 3D environment
*/
function Scene() {
this.shapes = {};
this.camera = new Point(0, 0, 0);
this.cameraTarget = new Point(0, 0, 0);
this.cameraRotation = 0;
this.drawlist = [];
}
/**
* Draw the world
*/
Scene.prototype.draw = function() {
space.push();
// Camera transformation
space.translate(
-this.camera.x,
-this.camera.y,
-this.camera.z
);
// Camera rotation
var xdiff = this.cameraTarget.x - this.camera.x;
var ydiff = this.cameraTarget.y - this.camera.y;
var zdiff = this.cameraTarget.z - this.camera.z;
var xzdist = Math.sqrt(Math.pow(xdiff, 2) + Math.pow(zdiff, 2));
var xrot = -Math.atan2(ydiff, xzdist); // up/down rotation
var yrot = Math.atan2(xdiff, zdiff); // left/right rotation
space.rotate(xrot, yrot, this.cameraRotation);
// Drawing
this.drawlist = [];
for(var i in this.shapes) {
this.shapes[i].draw(this.drawlist);
}
// Depth sorting (warning: this is only enough to drive this demo - feel
// free to contribute a better system).
this.drawlist.sort(function (poly1, poly2) {
return poly2.origin.tz - poly1.origin.tz;
});
for (var i = 0; i < this.drawlist.length; i++) {
this.drawlist[i].draw();
}
space.pop();
}
/* -------------------------------------------------------------------- */
var count = 0;
function loop() {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
scene.camera.x = 70*Math.sin(count);
scene.camera.y = 70;
scene.camera.z = 70*Math.cos(count);
scene.cameraRotation = count / 10;
count += 0.01;
scene.draw();
}
function load() {
// Init drawing system
canvas = document.getElementById("cv");
ctx = canvas.getContext("2d");
canvasWidth = canvas.width;
canvasHeight = canvas.height;
halfCanvasWidth = canvasWidth * 0.5;
halfCanvasHeight = canvasHeight * 0.5;
// Init 3D components
space = new Space();
scene = new Scene();
// Create a box shape and add it to the scene
scene.shapes['box'] = new Shape();
var p = scene.shapes['box'].points; // for convenience
p[0] = new Point(-10, -10, -10); // left bottom front
p[1] = new Point(10, -10, -10); // right bottom front
p[2] = new Point(10, 10, -10); // right top front
p[3] = new Point(-10, 10, -10); // left top front
p[4] = new Point(-10, -10, 10); // left bottom back
p[5] = new Point(10, -10, 10); // right bottom back
p[6] = new Point(10, 10, 10); // right top back
p[7] = new Point(-10, 10, 10); // left top back
// Back
scene.shapes['box'].polygons.push(new Polygon(
[ p[0], p[1], p[2], p[3] ],
new Point(0, 0, -1),
true /* double-sided */,
Polygon.SOLID,
[255, 0, 0]
));
// Front
scene.shapes['box'].polygons.push(new Polygon(
[ p[4], p[5], p[6], p[7] ],
new Point(0, 0, 1),
true /* double-sided */,
Polygon.SOLID,
[0, 0, 255]
));
// Top
scene.shapes['box'].polygons.push(new Polygon(
[ p[2], p[3], p[7], p[6] ],
new Point(0, 1, 0),
false /* single-sided */,
Polygon.WIRE,
[0, 255, 0]
));
// Transparent Top
scene.shapes['box'].polygons.push(new Polygon(
[ p[2], p[3], p[7], p[6] ],
new Point(0, 1, 0),
false /* single-sided */,
Polygon.SOLID,
[0, 255, 0, 0.4]
));
// Left
scene.shapes['box'].polygons.push(new Polygon(
[ p[0], p[4], p[7], p[3] ],
new Point(-1, 0, 0),
true /* double-sided */,
Polygon.SOLID,
[255, 255, 0]
));
// Right
scene.shapes['box'].polygons.push(new Polygon(
[ p[1], p[5], p[6], p[2] ],
new Point(1, 0, 0),
true /* double-sided */,
Polygon.SOLID,
[0, 255, 255]
));
// Create a floor shape and add it to the scene
scene.shapes['floor'] = new Shape();
var p = scene.shapes['floor'].points; // for convenience
p[0] = new Point(-40, -10, -40);
p[1] = new Point(-40, -10, 40);
p[2] = new Point( 40, -10, 40);
p[3] = new Point( 40, -10, -40);
// Floor
scene.shapes['floor'].polygons.push(new Polygon(
[ p[0], p[1], p[2], p[3] ],
new Point(0, 1, 0),
false /* single-sided */,
Polygon.SOLID,
[45, 45, 45]
));
setInterval('loop()', 20);
}
/* -------------------------------------------------------------------- */
</script>
<style>
body {
background-color:black;
margin:50px;
text-align:center;
}
</style>
</head>
<body onload="load();">
<canvas id="cv" width="400" height="300"></canvas>
</body>
</html>

View file

@ -0,0 +1,284 @@
<!DOCTYPE html>
<!--
Copyright 2006 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<style type="text/css">
body {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
}
#image-rotator {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#image-rotator .tool-bar {
text-align: center;
}
.tool-bar button {
margin: 0.5em 0.5em 0 0;
}
#image-rotator img,
#image-rotator canvas {
position: absolute;
}
</style>
<script type="text/javascript">
function sawFunc(a) {
var PI = Math.PI;
var PI2 = PI / 2;
// make sure a is within 0 to PI
a = a % PI;
if (a < 0) {
a += PI;
}
if (a < PI2) {
return a / PI2;
} else {
return (PI - a) / PI2;
}
}
function easeInEaseOut(t) {
var t2 = t * t;
return 3 * t2 - 2 * t * t2;
}
function ImageRotator(el, src, w, h) {
this.element = el;
this.toolBar = el.getElementsByTagName("div")[0];
this.canvas = el.getElementsByTagName("canvas")[0];
var images = el.getElementsByTagName("img");
this.image = images[images.length - 1];
var btns = el.getElementsByTagName("button");
this.btnCw = btns[0];
this.btnCcw = btns[1];
var self = this;
this.btnCcw.onclick = function () {
self.rotateCcw();
};
this.btnCw.onclick = function () {
self.rotateCw();
};
this.image.onload = function (e) {
self.onImageLoad(e);
};
this.image.onerror = function (e) {
self.onImageError(e);
};
this.image.onabort = function (e) {
self.onImageAbort(e);
};
this.setImage(src, w, h);
this.layout();
var onResize = function () {
self.layout();
};
var onLoad = function () {
self.onWindowLoad();
};
if (window.addEventListener) {
window.addEventListener("resize", onResize, false);
window.addEventListener("load", onLoad, false);
} else if (window.attachEvent) {
window.attachEvent("onresize", onResize);
window.attachEvent("onload", onLoad);
}
}
ImageRotator.prototype = {
getLoaded: function () {
return this.imageLoaded && this.windowLoaded;
},
setImage: function (src, w, h) {
this.imageLoaded = false;
this.image.src = src;
this.imageWidth = w;
this.imageHeight = h;
},
layout: function () {
var PI2 = Math.PI / 2;
var h = this.element.clientHeight;
var w = this.element.clientWidth;
var th = this.toolBar.offsetHeight;
h -= this.toolBar.offsetHeight;
if (!this.ctx || !this.getLoaded()) {
this.btnCw.disabled = true;
this.btnCcw.disabled = true;
this.canvas.style.display = "none";
this.image.style.display = "block";
var ratio = Math.min(w / this.imageWidth, h / this.imageHeight, 1);
var imgW = this.imageWidth * ratio;
var imgH = this.imageHeight * ratio;
var y = th + (h - imgH) / 2;
var x = (w - imgW) / 2;
this.image.style.left = Math.round(x) + "px";
this.image.style.top = Math.round(y) + "px";
this.image.style.width = Math.round(imgW) + "px";
this.image.style.height = Math.round(imgH) + "px";
} else {
this.btnCw.disabled = this.isAnimating_;
this.btnCcw.disabled = this.isAnimating_;
this.canvas.style.display = "block";
this.image.style.display = "none";
this.canvas.style.left = 0 + "px";
this.canvas.style.top = th + "px";
this.canvas.style.width = w + "px";
this.canvas.width = w;
this.canvas.style.height = h + "px";
this.canvas.height = h;
this.ctx.save();
this.ctx.clearRect(0, 0, w, h);
this.ctx.translate(w / 2, h / 2);
this.ctx.rotate(this.rotation);
// 0 -> 1, sin(0) = 0
// PI / 2 -> H / W, sin(PI/2) = 1
// sin(PI/2) = 1 -> limit factor is w and imgH
var iw = this.imageWidth;
var ih = this.imageHeight;
var scale;
if (iw <= w && iw <= h && ih <= h && ih <= w) {
scale = 1;
} else {
var sinr = sawFunc(this.rotation);
var cosr = sawFunc(this.rotation + PI2);
var ratio1 = sinr * Math.min(w / ih, h / iw);
var ratio2 = cosr * Math.min(w / iw, h / ih);
var ratio = Math.min(1, ratio1 + ratio2);
scale = ratio;
}
this.ctx.scale(scale, scale);
this.ctx.translate(-iw / 2, -ih / 2);
this.ctx.drawImage(this.image, 0, 0, iw, ih);
this.ctx.restore();
}
},
rotation: 0,
animationDuration: 500,
rotateCcw: function () {
if (!this.isAnimating_) {
this.startTime_ = (new Date).valueOf();
this.currentAngle_ = this.rotation;
this.deltaAngle_ = Math.PI / 2;
this.isAnimating_ = true;
this.animCounter_ = 0;
this.rotate_();
}
},
rotateCw: function () {
if (!this.isAnimating_) {
this.startTime_ = (new Date).valueOf();
this.currentAngle_ = this.rotation;
this.deltaAngle_ = -Math.PI / 2;
this.isAnimating_ = true;
this.animCounter_ = 0;
this.rotate_();
}
},
rotate_: function () {
if (this.isAnimating_) {
var t = easeInEaseOut(Math.min(1, (new Date - this.startTime_) /
this.animationDuration));
this.rotation = t * this.deltaAngle_ + this.currentAngle_;
if (t < 1) {
var self = this;
window.setTimeout(function () {
self.rotate_();
}, 10);
} else {
this.isAnimating_ = false;
}
this.layout();
}
},
onImageLoad: function (e) {
this.imageLoaded = true;
this.initCanvas();
},
onImageError: function (e) {
this.imageLoaded = false;
},
onImageAbort: function (e) {
this.imageLoaded = false;
},
onWindowLoad: function (e) {
this.windowLoaded = true;
this.initCanvas();
},
initCanvas: function () {
if (!this.ctx && this.getLoaded()) {
// IE recreates the element?
this.canvas = this.element.getElementsByTagName("canvas")[0];
this.ctx = this.canvas.getContext("2d");
if (!this.ctx) {
return;
}
this.layout();
}
}
};
</script>
</head>
<body>
<div id="image-rotator">
<div class="tool-bar">
<button>Rotate Left</button><button>Rotate Right</button>
</div>
<canvas id="c"></canvas>
<img src="" alt="">
</div>
<script type="text/javascript">
new ImageRotator(document.getElementById("image-rotator"),
"ff.jpg", 608, 380);
</script>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,93 @@
<!--
Copyright 2006 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<title>ExplorerCanvas Example 1</title>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script type="text/javascript">
var canvas, ctx;
var particles = [];
var NUM_PARTICLES = 20;
function Particle() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.xvel = Math.random() * 5 - 2.5;
this.yvel = Math.random() * 5 - 2.5;
}
Particle.prototype.update = function() {
this.x += this.xvel;
this.y += this.yvel;
this.yvel += 0.1;
if (this.x > canvas.width || this.x < 0) {
this.xvel = -this.xvel;
}
if (this.y > canvas.height || this.y < 0) {
this.yvel = -this.yvel;
}
}
function loop() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = 0; i < NUM_PARTICLES; i++) {
particles[i].update();
ctx.beginPath();
ctx.moveTo(particles[i].x, particles[i].y);
ctx.lineTo(particles[i].x - particles[i].xvel,
particles[i].y - particles[i].yvel);
ctx.stroke();
ctx.closePath();
}
setTimeout(loop, 10);
}
function load() {
canvas = document.getElementById("cv");
ctx = canvas.getContext("2d");
for(var i = 0; i < NUM_PARTICLES; i++) {
particles[i] = new Particle();
}
ctx.lineWidth = "2";
ctx.strokeStyle = "rgb(255, 255, 255)";
loop();
}
</script>
<style>
body {
background-color:black;
margin:50px;
text-align:center;
}
canvas {
border:1px solid #444;
}
</style>
</head>
<body onload="load();">
<canvas id="cv" width="400" height="300"></canvas>
</body>
</html>

View file

@ -0,0 +1,513 @@
<!--
Copyright 2006 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<title>ExplorerCanvas Example 1</title>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script type="text/javascript">
/* -------------------------------------------------------------------- */
var canvas, ctx;
var canvasWidth, halfCanvasWidth;
var canvasHeight, halfCanvasHeight;
var space; // 3D Engine
var scene; // 3D Scene
/* -------------------------------------------------------------------- */
/**
* Space is a simple 3D system.
*
* Y+ = up
* Z+ = into screen
* X+ = right
*/
function Space() {
this.m = this.createMatrixIdentity();
this.mStack = [];
}
Space.prototype.createMatrixIdentity = function() {
return [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
];
}
/**
* Multiplies two 4x4 matricies together.
*/
Space.prototype.matrixMultiply = function(m1, m2) {
var result = this.createMatrixIdentity();
var width = m1[0].length;
var height = m1.length;
if (width != m2.length) {
// error
}
for (var x = 0; x < width; x++) {
for (var y = 0; y < height; y++) {
var sum = 0;
for (var z = 0; z < width; z++) {
sum += m1[y][z] * m2[z][x];
}
result[y][x] = sum;
}
}
return result;
}
/**
* Transforms a coordinate using the current transformation
* matrix, then flattens it using the projection matrix.
*/
Space.prototype.flatten = function(point) {
var p = [[point.x, point.y, point.z, 1]];
var pm = this.matrixMultiply(p, this.m);
point.tx = pm[0][0];
point.ty = pm[0][1];
point.tz = pm[0][2];
// lazy projection
point.fx = halfCanvasWidth + (canvasWidth * point.tx / point.tz);
point.fy = halfCanvasHeight -(canvasWidth * point.ty / point.tz);
}
/**
* Translate (move) the current transformation matrix
*/
Space.prototype.translate = function(x, y, z) {
var m = [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[x, y, z, 1]
];
this.m = this.matrixMultiply(m, this.m);
}
/**
* Rotate the current transformation matrix. Rotations are
* world-oriented, and occur in y,x,z order.
*/
Space.prototype.rotate = function(x, y, z) {
if (y) {
var cosY = Math.cos(y);
var sinY = Math.sin(y);
var rotY = [
[cosY, 0, sinY, 0],
[0, 1, 0, 0],
[-sinY, 0, cosY, 0],
[0, 0, 0, 1]
];
this.m = this.matrixMultiply(this.m, rotY);
}
if (x) {
var cosX = Math.cos(x);
var sinX = Math.sin(x);
var rotX = [
[1, 0, 0, 0],
[0, cosX, -sinX, 0],
[0, sinX, cosX,0],
[0, 0, 0, 1]
];
this.m = this.matrixMultiply(this.m, rotX);
}
if (z) {
var cosZ = Math.cos(z);
var sinZ = Math.sin(z);
var rotZ = [
[cosZ, -sinZ, 0, 0],
[sinZ, cosZ, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
];
this.m = this.matrixMultiply(this.m, rotZ);
}
}
/**
* Pushes the current transformation onto the stack
*/
Space.prototype.push = function() {
this.mStack.push(this.m);
this.m = [
[this.m[0][0], this.m[0][1], this.m[0][2], this.m[0][3]],
[this.m[1][0], this.m[1][1], this.m[1][2], this.m[1][3]],
[this.m[2][0], this.m[2][1], this.m[2][2], this.m[2][3]],
[this.m[3][0], this.m[3][1], this.m[3][2], this.m[3][3]]
];
}
/**
* Pops the end off the transformation stack
*/
Space.prototype.pop = function() {
this.m = this.mStack.pop();
}
/* -------------------------------------------------------------------- */
/**
* A 3d coordinate
*/
function Point(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
// Relative to camera coordinates
this.tx;
this.ty;
this.tz;
// Flattened coordinates
this.fx;
this.fy;
}
/**
* A Shape is made up of polygons
*/
function Shape() {
this.points = [];
this.polygons = [];
}
/**
* Draws the shape
*/
Shape.prototype.draw = function(drawlist) {
for (var i = 0; i< this.points.length; i++) {
space.flatten(this.points[i]);
}
for (var i = 0; i< this.polygons.length; i++) {
var poly = this.polygons[i]; // convenience
space.flatten(poly.origin);
// lazy backface culling
if (poly.normal && this.backface) {
space.flatten(poly.normal);
var originDist = Math.pow(poly.origin.tx, 2)
+ Math.pow(poly.origin.ty, 2)
+ Math.pow(poly.origin.tz, 2);
var normalDist = Math.pow(poly.normal.tx, 2)
+ Math.pow(poly.normal.ty, 2)
+ Math.pow(poly.normal.tz, 2);
if(originDist > normalDist) {
drawlist.push(poly);
}
} else {
drawlist.push(poly);
}
}
}
/**
* A polygon is a connection of points in the shape object. You
* should probably try to make them coplanar.
*/
function Polygon(points, normal, backface, type, color) {
this.points = points;
this.origin = new Point(0, 0, 0);
for(var i = 0; i < this.points.length; i++) {
this.origin.x += this.points[i].x;
this.origin.y += this.points[i].y;
this.origin.z += this.points[i].z;
}
this.origin.x /= this.points.length;
this.origin.y /= this.points.length;
this.origin.z /= this.points.length;
if (normal) {
this.normal = new Point(this.origin.x + normal.x,
this.origin.y + normal.y,
this.origin.z + normal.z);
} else {
this.normal = null;
}
this.backface = backface;
this.type = type;
this.color = color;
}
Polygon.SOLID = 0;
Polygon.WIRE = 1;
/**
* Draws the polygon. Assumes that the points have already been
* flattened.
*/
Polygon.prototype.draw = function() {
ctx.beginPath();
ctx.moveTo(this.points[0].fx, this.points[0].fy);
for(var i = 0; i < this.points.length; i++) {
ctx.lineTo(this.points[i].fx, this.points[i].fy);
}
ctx.closePath();
var color = this.color;
/*
// Do lighting here
lightvector = Math.abs(this.normal.x + this.normal.y);
if(lightvector > 1) {
lightvector = 1;
}
color[0] = (color[0] * lightvector).toString();
color[1] = (color[1] * lightvector).toString();
color[2] = (color[2] * lightvector).toString();
*/
if (color.length > 3) {
var style = ["rgba(",
color[0], ",",
color[1], ",",
color[2], ",",
color[3], ")"].join("");
} else {
var style = ["rgb(",
color[0], ",",
color[1], ",",
color[2], ")"].join("");
}
if (this.type == Polygon.SOLID) {
ctx.fillStyle = style;
ctx.fill();
} else if (this.type == Polygon.WIRE) {
ctx.strokeStyle = style;
ctx.stroke();
}
}
/* -------------------------------------------------------------------- */
/**
* Scene describes the 3D environment
*/
function Scene() {
this.shapes = {};
this.camera = new Point(0, 0, 0);
this.cameraTarget = new Point(0, 0, 0);
this.cameraRotation = 0;
this.drawlist = [];
}
/**
* Draw the world
*/
Scene.prototype.draw = function() {
space.push();
// Camera transformation
space.translate(
-this.camera.x,
-this.camera.y,
-this.camera.z
);
// Camera rotation
var xdiff = this.cameraTarget.x - this.camera.x;
var ydiff = this.cameraTarget.y - this.camera.y;
var zdiff = this.cameraTarget.z - this.camera.z;
var xzdist = Math.sqrt(Math.pow(xdiff, 2) + Math.pow(zdiff, 2));
var xrot = -Math.atan2(ydiff, xzdist); // up/down rotation
var yrot = Math.atan2(xdiff, zdiff); // left/right rotation
space.rotate(xrot, yrot, this.cameraRotation);
// Drawing
this.drawlist = [];
for(var i in this.shapes) {
this.shapes[i].draw(this.drawlist);
}
// Depth sorting (warning: this is only enough to drive this demo - feel
// free to contribute a better system).
this.drawlist.sort(function (poly1, poly2) {
return poly2.origin.tz - poly1.origin.tz;
});
for (var i = 0; i < this.drawlist.length; i++) {
this.drawlist[i].draw();
}
space.pop();
}
/* -------------------------------------------------------------------- */
var count = 0;
function loop() {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
scene.camera.x = 70*Math.sin(count);
scene.camera.y = 70;
scene.camera.z = 70*Math.cos(count);
scene.cameraRotation = count / 10;
count += 0.01;
scene.draw();
}
function load() {
// Init drawing system
canvas = document.getElementById("cv");
ctx = canvas.getContext("2d");
canvasWidth = canvas.width;
canvasHeight = canvas.height;
halfCanvasWidth = canvasWidth * 0.5;
halfCanvasHeight = canvasHeight * 0.5;
// Init 3D components
space = new Space();
scene = new Scene();
// Create a box shape and add it to the scene
scene.shapes['box'] = new Shape();
var p = scene.shapes['box'].points; // for convenience
p[0] = new Point(-10, -10, -10); // left bottom front
p[1] = new Point(10, -10, -10); // right bottom front
p[2] = new Point(10, 10, -10); // right top front
p[3] = new Point(-10, 10, -10); // left top front
p[4] = new Point(-10, -10, 10); // left bottom back
p[5] = new Point(10, -10, 10); // right bottom back
p[6] = new Point(10, 10, 10); // right top back
p[7] = new Point(-10, 10, 10); // left top back
// Back
scene.shapes['box'].polygons.push(new Polygon(
[ p[0], p[1], p[2], p[3] ],
new Point(0, 0, -1),
true /* double-sided */,
Polygon.SOLID,
[255, 0, 0]
));
// Front
scene.shapes['box'].polygons.push(new Polygon(
[ p[4], p[5], p[6], p[7] ],
new Point(0, 0, 1),
true /* double-sided */,
Polygon.SOLID,
[0, 0, 255]
));
// Top
scene.shapes['box'].polygons.push(new Polygon(
[ p[2], p[3], p[7], p[6] ],
new Point(0, 1, 0),
false /* single-sided */,
Polygon.WIRE,
[0, 255, 0]
));
// Transparent Top
scene.shapes['box'].polygons.push(new Polygon(
[ p[2], p[3], p[7], p[6] ],
new Point(0, 1, 0),
false /* single-sided */,
Polygon.SOLID,
[0, 255, 0, 0.4]
));
// Left
scene.shapes['box'].polygons.push(new Polygon(
[ p[0], p[4], p[7], p[3] ],
new Point(-1, 0, 0),
true /* double-sided */,
Polygon.SOLID,
[255, 255, 0]
));
// Right
scene.shapes['box'].polygons.push(new Polygon(
[ p[1], p[5], p[6], p[2] ],
new Point(1, 0, 0),
true /* double-sided */,
Polygon.SOLID,
[0, 255, 255]
));
// Create a floor shape and add it to the scene
scene.shapes['floor'] = new Shape();
var p = scene.shapes['floor'].points; // for convenience
p[0] = new Point(-40, -10, -40);
p[1] = new Point(-40, -10, 40);
p[2] = new Point( 40, -10, 40);
p[3] = new Point( 40, -10, -40);
// Floor
scene.shapes['floor'].polygons.push(new Polygon(
[ p[0], p[1], p[2], p[3] ],
new Point(0, 1, 0),
false /* single-sided */,
Polygon.SOLID,
[45, 45, 45]
));
setInterval('loop()', 20);
}
/* -------------------------------------------------------------------- */
</script>
<style>
body {
background-color:black;
margin:50px;
text-align:center;
}
</style>
</head>
<body onload="load();">
<canvas id="cv" width="400" height="300"></canvas>
</body>
</html>

View file

@ -0,0 +1,284 @@
<!DOCTYPE html>
<!--
Copyright 2006 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<style type="text/css">
body {
overflow: hidden;
width: 100%;
height: 100%;
margin: 0;
}
#image-rotator {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#image-rotator .tool-bar {
text-align: center;
}
.tool-bar button {
margin: 0.5em 0.5em 0 0;
}
#image-rotator img,
#image-rotator canvas {
position: absolute;
}
</style>
<script type="text/javascript">
function sawFunc(a) {
var PI = Math.PI;
var PI2 = PI / 2;
// make sure a is within 0 to PI
a = a % PI;
if (a < 0) {
a += PI;
}
if (a < PI2) {
return a / PI2;
} else {
return (PI - a) / PI2;
}
}
function easeInEaseOut(t) {
var t2 = t * t;
return 3 * t2 - 2 * t * t2;
}
function ImageRotator(el, src, w, h) {
this.element = el;
this.toolBar = el.getElementsByTagName("div")[0];
this.canvas = el.getElementsByTagName("canvas")[0];
var images = el.getElementsByTagName("img");
this.image = images[images.length - 1];
var btns = el.getElementsByTagName("button");
this.btnCw = btns[0];
this.btnCcw = btns[1];
var self = this;
this.btnCcw.onclick = function () {
self.rotateCcw();
};
this.btnCw.onclick = function () {
self.rotateCw();
};
this.image.onload = function (e) {
self.onImageLoad(e);
};
this.image.onerror = function (e) {
self.onImageError(e);
};
this.image.onabort = function (e) {
self.onImageAbort(e);
};
this.setImage(src, w, h);
this.layout();
var onResize = function () {
self.layout();
};
var onLoad = function () {
self.onWindowLoad();
};
if (window.addEventListener) {
window.addEventListener("resize", onResize, false);
window.addEventListener("load", onLoad, false);
} else if (window.attachEvent) {
window.attachEvent("onresize", onResize);
window.attachEvent("onload", onLoad);
}
}
ImageRotator.prototype = {
getLoaded: function () {
return this.imageLoaded && this.windowLoaded;
},
setImage: function (src, w, h) {
this.imageLoaded = false;
this.image.src = src;
this.imageWidth = w;
this.imageHeight = h;
},
layout: function () {
var PI2 = Math.PI / 2;
var h = this.element.clientHeight;
var w = this.element.clientWidth;
var th = this.toolBar.offsetHeight;
h -= this.toolBar.offsetHeight;
if (!this.ctx || !this.getLoaded()) {
this.btnCw.disabled = true;
this.btnCcw.disabled = true;
this.canvas.style.display = "none";
this.image.style.display = "block";
var ratio = Math.min(w / this.imageWidth, h / this.imageHeight, 1);
var imgW = this.imageWidth * ratio;
var imgH = this.imageHeight * ratio;
var y = th + (h - imgH) / 2;
var x = (w - imgW) / 2;
this.image.style.left = Math.round(x) + "px";
this.image.style.top = Math.round(y) + "px";
this.image.style.width = Math.round(imgW) + "px";
this.image.style.height = Math.round(imgH) + "px";
} else {
this.btnCw.disabled = this.isAnimating_;
this.btnCcw.disabled = this.isAnimating_;
this.canvas.style.display = "block";
this.image.style.display = "none";
this.canvas.style.left = 0 + "px";
this.canvas.style.top = th + "px";
this.canvas.style.width = w + "px";
this.canvas.width = w;
this.canvas.style.height = h + "px";
this.canvas.height = h;
this.ctx.save();
this.ctx.clearRect(0, 0, w, h);
this.ctx.translate(w / 2, h / 2);
this.ctx.rotate(this.rotation);
// 0 -> 1, sin(0) = 0
// PI / 2 -> H / W, sin(PI/2) = 1
// sin(PI/2) = 1 -> limit factor is w and imgH
var iw = this.imageWidth;
var ih = this.imageHeight;
var scale;
if (iw <= w && iw <= h && ih <= h && ih <= w) {
scale = 1;
} else {
var sinr = sawFunc(this.rotation);
var cosr = sawFunc(this.rotation + PI2);
var ratio1 = sinr * Math.min(w / ih, h / iw);
var ratio2 = cosr * Math.min(w / iw, h / ih);
var ratio = Math.min(1, ratio1 + ratio2);
scale = ratio;
}
this.ctx.scale(scale, scale);
this.ctx.translate(-iw / 2, -ih / 2);
this.ctx.drawImage(this.image, 0, 0, iw, ih);
this.ctx.restore();
}
},
rotation: 0,
animationDuration: 500,
rotateCcw: function () {
if (!this.isAnimating_) {
this.startTime_ = (new Date).valueOf();
this.currentAngle_ = this.rotation;
this.deltaAngle_ = Math.PI / 2;
this.isAnimating_ = true;
this.animCounter_ = 0;
this.rotate_();
}
},
rotateCw: function () {
if (!this.isAnimating_) {
this.startTime_ = (new Date).valueOf();
this.currentAngle_ = this.rotation;
this.deltaAngle_ = -Math.PI / 2;
this.isAnimating_ = true;
this.animCounter_ = 0;
this.rotate_();
}
},
rotate_: function () {
if (this.isAnimating_) {
var t = easeInEaseOut(Math.min(1, (new Date - this.startTime_) /
this.animationDuration));
this.rotation = t * this.deltaAngle_ + this.currentAngle_;
if (t < 1) {
var self = this;
window.setTimeout(function () {
self.rotate_();
}, 10);
} else {
this.isAnimating_ = false;
}
this.layout();
}
},
onImageLoad: function (e) {
this.imageLoaded = true;
this.initCanvas();
},
onImageError: function (e) {
this.imageLoaded = false;
},
onImageAbort: function (e) {
this.imageLoaded = false;
},
onWindowLoad: function (e) {
this.windowLoaded = true;
this.initCanvas();
},
initCanvas: function () {
if (!this.ctx && this.getLoaded()) {
// IE recreates the element?
this.canvas = this.element.getElementsByTagName("canvas")[0];
this.ctx = this.canvas.getContext("2d");
if (!this.ctx) {
return;
}
this.layout();
}
}
};
</script>
</head>
<body>
<div id="image-rotator">
<div class="tool-bar">
<button>Rotate Left</button><button>Rotate Right</button>
</div>
<canvas id="c"></canvas>
<img src="" alt="">
</div>
<script type="text/javascript">
new ImageRotator(document.getElementById("image-rotator"),
"ff.jpg", 608, 380);
</script>
</body>
</html>

BIN
excanvas_r3/examples/ff.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,35 @@
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
document.createElement("canvas").getContext||(function(){var s=Math,j=s.round,F=s.sin,G=s.cos,V=s.abs,W=s.sqrt,k=10,v=k/2;function X(){return this.context_||(this.context_=new H(this))}var L=Array.prototype.slice;function Y(b,a){var c=L.call(arguments,2);return function(){return b.apply(a,c.concat(L.call(arguments)))}}var M={init:function(b){if(/MSIE/.test(navigator.userAgent)&&!window.opera){var a=b||document;a.createElement("canvas");a.attachEvent("onreadystatechange",Y(this.init_,this,a))}},init_:function(b){b.namespaces.g_vml_||
b.namespaces.add("g_vml_","urn:schemas-microsoft-com:vml","#default#VML");b.namespaces.g_o_||b.namespaces.add("g_o_","urn:schemas-microsoft-com:office:office","#default#VML");if(!b.styleSheets.ex_canvas_){var a=b.createStyleSheet();a.owningElement.id="ex_canvas_";a.cssText="canvas{display:inline-block;overflow:hidden;text-align:left;width:300px;height:150px}g_vml_\\:*{behavior:url(#default#VML)}g_o_\\:*{behavior:url(#default#VML)}"}var c=b.getElementsByTagName("canvas"),d=0;for(;d<c.length;d++)this.initElement(c[d])},
initElement:function(b){if(!b.getContext){b.getContext=X;b.innerHTML="";b.attachEvent("onpropertychange",Z);b.attachEvent("onresize",$);var a=b.attributes;if(a.width&&a.width.specified)b.style.width=a.width.nodeValue+"px";else b.width=b.clientWidth;if(a.height&&a.height.specified)b.style.height=a.height.nodeValue+"px";else b.height=b.clientHeight}return b}};function Z(b){var a=b.srcElement;switch(b.propertyName){case "width":a.style.width=a.attributes.width.nodeValue+"px";a.getContext().clearRect();
break;case "height":a.style.height=a.attributes.height.nodeValue+"px";a.getContext().clearRect();break}}function $(b){var a=b.srcElement;if(a.firstChild){a.firstChild.style.width=a.clientWidth+"px";a.firstChild.style.height=a.clientHeight+"px"}}M.init();var N=[],B=0;for(;B<16;B++){var C=0;for(;C<16;C++)N[B*16+C]=B.toString(16)+C.toString(16)}function I(){return[[1,0,0],[0,1,0],[0,0,1]]}function y(b,a){var c=I(),d=0;for(;d<3;d++){var f=0;for(;f<3;f++){var h=0,g=0;for(;g<3;g++)h+=b[d][g]*a[g][f];c[d][f]=
h}}return c}function O(b,a){a.fillStyle=b.fillStyle;a.lineCap=b.lineCap;a.lineJoin=b.lineJoin;a.lineWidth=b.lineWidth;a.miterLimit=b.miterLimit;a.shadowBlur=b.shadowBlur;a.shadowColor=b.shadowColor;a.shadowOffsetX=b.shadowOffsetX;a.shadowOffsetY=b.shadowOffsetY;a.strokeStyle=b.strokeStyle;a.globalAlpha=b.globalAlpha;a.arcScaleX_=b.arcScaleX_;a.arcScaleY_=b.arcScaleY_;a.lineScale_=b.lineScale_}function P(b){var a,c=1;b=String(b);if(b.substring(0,3)=="rgb"){var d=b.indexOf("(",3),f=b.indexOf(")",d+
1),h=b.substring(d+1,f).split(",");a="#";var g=0;for(;g<3;g++)a+=N[Number(h[g])];if(h.length==4&&b.substr(3,1)=="a")c=h[3]}else a=b;return{color:a,alpha:c}}function aa(b){switch(b){case "butt":return"flat";case "round":return"round";case "square":default:return"square"}}function H(b){this.m_=I();this.mStack_=[];this.aStack_=[];this.currentPath_=[];this.fillStyle=this.strokeStyle="#000";this.lineWidth=1;this.lineJoin="miter";this.lineCap="butt";this.miterLimit=k*1;this.globalAlpha=1;this.canvas=b;
var a=b.ownerDocument.createElement("div");a.style.width=b.clientWidth+"px";a.style.height=b.clientHeight+"px";a.style.overflow="hidden";a.style.position="absolute";b.appendChild(a);this.element_=a;this.lineScale_=this.arcScaleY_=this.arcScaleX_=1}var i=H.prototype;i.clearRect=function(){this.element_.innerHTML=""};i.beginPath=function(){this.currentPath_=[]};i.moveTo=function(b,a){var c=this.getCoords_(b,a);this.currentPath_.push({type:"moveTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};
i.lineTo=function(b,a){var c=this.getCoords_(b,a);this.currentPath_.push({type:"lineTo",x:c.x,y:c.y});this.currentX_=c.x;this.currentY_=c.y};i.bezierCurveTo=function(b,a,c,d,f,h){var g=this.getCoords_(f,h),l=this.getCoords_(b,a),e=this.getCoords_(c,d);Q(this,l,e,g)};function Q(b,a,c,d){b.currentPath_.push({type:"bezierCurveTo",cp1x:a.x,cp1y:a.y,cp2x:c.x,cp2y:c.y,x:d.x,y:d.y});b.currentX_=d.x;b.currentY_=d.y}i.quadraticCurveTo=function(b,a,c,d){var f=this.getCoords_(b,a),h=this.getCoords_(c,d),g={x:this.currentX_+
0.6666666666666666*(f.x-this.currentX_),y:this.currentY_+0.6666666666666666*(f.y-this.currentY_)};Q(this,g,{x:g.x+(h.x-this.currentX_)/3,y:g.y+(h.y-this.currentY_)/3},h)};i.arc=function(b,a,c,d,f,h){c*=k;var g=h?"at":"wa",l=b+G(d)*c-v,e=a+F(d)*c-v,m=b+G(f)*c-v,r=a+F(f)*c-v;if(l==m&&!h)l+=0.125;var n=this.getCoords_(b,a),o=this.getCoords_(l,e),q=this.getCoords_(m,r);this.currentPath_.push({type:g,x:n.x,y:n.y,radius:c,xStart:o.x,yStart:o.y,xEnd:q.x,yEnd:q.y})};i.rect=function(b,a,c,d){this.moveTo(b,
a);this.lineTo(b+c,a);this.lineTo(b+c,a+d);this.lineTo(b,a+d);this.closePath()};i.strokeRect=function(b,a,c,d){var f=this.currentPath_;this.beginPath();this.moveTo(b,a);this.lineTo(b+c,a);this.lineTo(b+c,a+d);this.lineTo(b,a+d);this.closePath();this.stroke();this.currentPath_=f};i.fillRect=function(b,a,c,d){var f=this.currentPath_;this.beginPath();this.moveTo(b,a);this.lineTo(b+c,a);this.lineTo(b+c,a+d);this.lineTo(b,a+d);this.closePath();this.fill();this.currentPath_=f};i.createLinearGradient=function(b,
a,c,d){var f=new D("gradient");f.x0_=b;f.y0_=a;f.x1_=c;f.y1_=d;return f};i.createRadialGradient=function(b,a,c,d,f,h){var g=new D("gradientradial");g.x0_=b;g.y0_=a;g.r0_=c;g.x1_=d;g.y1_=f;g.r1_=h;return g};i.drawImage=function(b){var a,c,d,f,h,g,l,e,m=b.runtimeStyle.width,r=b.runtimeStyle.height;b.runtimeStyle.width="auto";b.runtimeStyle.height="auto";var n=b.width,o=b.height;b.runtimeStyle.width=m;b.runtimeStyle.height=r;if(arguments.length==3){a=arguments[1];c=arguments[2];h=g=0;l=d=n;e=f=o}else if(arguments.length==
5){a=arguments[1];c=arguments[2];d=arguments[3];f=arguments[4];h=g=0;l=n;e=o}else if(arguments.length==9){h=arguments[1];g=arguments[2];l=arguments[3];e=arguments[4];a=arguments[5];c=arguments[6];d=arguments[7];f=arguments[8]}else throw Error("Invalid number of arguments");var q=this.getCoords_(a,c),t=[];t.push(" <g_vml_:group",' coordsize="',k*10,",",k*10,'"',' coordorigin="0,0"',' style="width:',10,"px;height:",10,"px;position:absolute;");if(this.m_[0][0]!=1||this.m_[0][1]){var E=[];E.push("M11=",
this.m_[0][0],",","M12=",this.m_[1][0],",","M21=",this.m_[0][1],",","M22=",this.m_[1][1],",","Dx=",j(q.x/k),",","Dy=",j(q.y/k),"");var p=q,z=this.getCoords_(a+d,c),w=this.getCoords_(a,c+f),x=this.getCoords_(a+d,c+f);p.x=s.max(p.x,z.x,w.x,x.x);p.y=s.max(p.y,z.y,w.y,x.y);t.push("padding:0 ",j(p.x/k),"px ",j(p.y/k),"px 0;filter:progid:DXImageTransform.Microsoft.Matrix(",E.join(""),", sizingmethod='clip');")}else t.push("top:",j(q.y/k),"px;left:",j(q.x/k),"px;");t.push(' ">','<g_vml_:image src="',b.src,
'"',' style="width:',k*d,"px;"," height:",k*f,'px;"',' cropleft="',h/n,'"',' croptop="',g/o,'"',' cropright="',(n-h-l)/n,'"',' cropbottom="',(o-g-e)/o,'"'," />","</g_vml_:group>");this.element_.insertAdjacentHTML("BeforeEnd",t.join(""))};i.stroke=function(b){var a=[],c=P(b?this.fillStyle:this.strokeStyle),d=c.color,f=c.alpha*this.globalAlpha;a.push("<g_vml_:shape",' filled="',!!b,'"',' style="position:absolute;width:',10,"px;height:",10,'px;"',' coordorigin="0 0" coordsize="',k*10," ",k*10,'"',' stroked="',
!b,'"',' path="');var h={x:null,y:null},g={x:null,y:null},l=0;for(;l<this.currentPath_.length;l++){var e=this.currentPath_[l];switch(e.type){case "moveTo":a.push(" m ",j(e.x),",",j(e.y));break;case "lineTo":a.push(" l ",j(e.x),",",j(e.y));break;case "close":a.push(" x ");e=null;break;case "bezierCurveTo":a.push(" c ",j(e.cp1x),",",j(e.cp1y),",",j(e.cp2x),",",j(e.cp2y),",",j(e.x),",",j(e.y));break;case "at":case "wa":a.push(" ",e.type," ",j(e.x-this.arcScaleX_*e.radius),",",j(e.y-this.arcScaleY_*e.radius),
" ",j(e.x+this.arcScaleX_*e.radius),",",j(e.y+this.arcScaleY_*e.radius)," ",j(e.xStart),",",j(e.yStart)," ",j(e.xEnd),",",j(e.yEnd));break}if(e){if(h.x==null||e.x<h.x)h.x=e.x;if(g.x==null||e.x>g.x)g.x=e.x;if(h.y==null||e.y<h.y)h.y=e.y;if(g.y==null||e.y>g.y)g.y=e.y}}a.push(' ">');if(b)if(typeof this.fillStyle=="object"){var m=this.fillStyle,r=0,n={x:0,y:0},o=0,q=1;if(m.type_=="gradient"){var t=m.x1_/this.arcScaleX_,E=m.y1_/this.arcScaleY_,p=this.getCoords_(m.x0_/this.arcScaleX_,m.y0_/this.arcScaleY_),
z=this.getCoords_(t,E);r=Math.atan2(z.x-p.x,z.y-p.y)*180/Math.PI;if(r<0)r+=360;if(r<1.0E-6)r=0}else{var p=this.getCoords_(m.x0_,m.y0_),w=g.x-h.x,x=g.y-h.y;n={x:(p.x-h.x)/w,y:(p.y-h.y)/x};w/=this.arcScaleX_*k;x/=this.arcScaleY_*k;var R=s.max(w,x);o=2*m.r0_/R;q=2*m.r1_/R-o}var u=m.colors_;u.sort(function(ba,ca){return ba.offset-ca.offset});var J=u.length,da=u[0].color,ea=u[J-1].color,fa=u[0].alpha*this.globalAlpha,ga=u[J-1].alpha*this.globalAlpha,S=[],l=0;for(;l<J;l++){var T=u[l];S.push(T.offset*q+
o+" "+T.color)}a.push('<g_vml_:fill type="',m.type_,'"',' method="none" focus="100%"',' color="',da,'"',' color2="',ea,'"',' colors="',S.join(","),'"',' opacity="',ga,'"',' g_o_:opacity2="',fa,'"',' angle="',r,'"',' focusposition="',n.x,",",n.y,'" />')}else a.push('<g_vml_:fill color="',d,'" opacity="',f,'" />');else{var K=this.lineScale_*this.lineWidth;if(K<1)f*=K;a.push("<g_vml_:stroke",' opacity="',f,'"',' joinstyle="',this.lineJoin,'"',' miterlimit="',this.miterLimit,'"',' endcap="',aa(this.lineCap),
'"',' weight="',K,'px"',' color="',d,'" />')}a.push("</g_vml_:shape>");this.element_.insertAdjacentHTML("beforeEnd",a.join(""))};i.fill=function(){this.stroke(true)};i.closePath=function(){this.currentPath_.push({type:"close"})};i.getCoords_=function(b,a){var c=this.m_;return{x:k*(b*c[0][0]+a*c[1][0]+c[2][0])-v,y:k*(b*c[0][1]+a*c[1][1]+c[2][1])-v}};i.save=function(){var b={};O(this,b);this.aStack_.push(b);this.mStack_.push(this.m_);this.m_=y(I(),this.m_)};i.restore=function(){O(this.aStack_.pop(),
this);this.m_=this.mStack_.pop()};function ha(b){var a=0;for(;a<3;a++){var c=0;for(;c<2;c++)if(!isFinite(b[a][c])||isNaN(b[a][c]))return false}return true}function A(b,a,c){if(!!ha(a)){b.m_=a;if(c)b.lineScale_=W(V(a[0][0]*a[1][1]-a[0][1]*a[1][0]))}}i.translate=function(b,a){A(this,y([[1,0,0],[0,1,0],[b,a,1]],this.m_),false)};i.rotate=function(b){var a=G(b),c=F(b);A(this,y([[a,c,0],[-c,a,0],[0,0,1]],this.m_),false)};i.scale=function(b,a){this.arcScaleX_*=b;this.arcScaleY_*=a;A(this,y([[b,0,0],[0,a,
0],[0,0,1]],this.m_),true)};i.transform=function(b,a,c,d,f,h){A(this,y([[b,a,0],[c,d,0],[f,h,1]],this.m_),true)};i.setTransform=function(b,a,c,d,f,h){A(this,[[b,a,0],[c,d,0],[f,h,1]],true)};i.clip=function(){};i.arcTo=function(){};i.createPattern=function(){return new U};function D(b){this.type_=b;this.r1_=this.y1_=this.x1_=this.r0_=this.y0_=this.x0_=0;this.colors_=[]}D.prototype.addColorStop=function(b,a){a=P(a);this.colors_.push({offset:b,color:a.color,alpha:a.alpha})};function U(){}G_vmlCanvasManager=
M;CanvasRenderingContext2D=H;CanvasGradient=D;CanvasPattern=U})();

924
excanvas_r3/excanvas.js Normal file
View file

@ -0,0 +1,924 @@
// Copyright 2006 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Known Issues:
//
// * Patterns are not implemented.
// * Radial gradient are not implemented. The VML version of these look very
// different from the canvas one.
// * Clipping paths are not implemented.
// * Coordsize. The width and height attribute have higher priority than the
// width and height style values which isn't correct.
// * Painting mode isn't implemented.
// * Canvas width/height should is using content-box by default. IE in
// Quirks mode will draw the canvas using border-box. Either change your
// doctype to HTML5
// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype)
// or use Box Sizing Behavior from WebFX
// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html)
// * Non uniform scaling does not correctly scale strokes.
// * Optimize. There is always room for speed improvements.
// Only add this code if we do not already have a canvas implementation
if (!document.createElement('canvas').getContext) {
(function() {
// alias some functions to make (compiled) code shorter
var m = Math;
var mr = m.round;
var ms = m.sin;
var mc = m.cos;
var abs = m.abs;
var sqrt = m.sqrt;
// this is used for sub pixel precision
var Z = 10;
var Z2 = Z / 2;
/**
* This funtion is assigned to the <canvas> elements as element.getContext().
* @this {HTMLElement}
* @return {CanvasRenderingContext2D_}
*/
function getContext() {
return this.context_ ||
(this.context_ = new CanvasRenderingContext2D_(this));
}
var slice = Array.prototype.slice;
/**
* Binds a function to an object. The returned function will always use the
* passed in {@code obj} as {@code this}.
*
* Example:
*
* g = bind(f, obj, a, b)
* g(c, d) // will do f.call(obj, a, b, c, d)
*
* @param {Function} f The function to bind the object to
* @param {Object} obj The object that should act as this when the function
* is called
* @param {*} var_args Rest arguments that will be used as the initial
* arguments when the function is called
* @return {Function} A new function that has bound this
*/
function bind(f, obj, var_args) {
var a = slice.call(arguments, 2);
return function() {
return f.apply(obj, a.concat(slice.call(arguments)));
};
}
var G_vmlCanvasManager_ = {
init: function(opt_doc) {
if (/MSIE/.test(navigator.userAgent) && !window.opera) {
var doc = opt_doc || document;
// Create a dummy element so that IE will allow canvas elements to be
// recognized.
doc.createElement('canvas');
doc.attachEvent('onreadystatechange', bind(this.init_, this, doc));
}
},
init_: function(doc) {
// create xmlns
if (!doc.namespaces['g_vml_']) {
doc.namespaces.add('g_vml_', 'urn:schemas-microsoft-com:vml',
'#default#VML');
}
if (!doc.namespaces['g_o_']) {
doc.namespaces.add('g_o_', 'urn:schemas-microsoft-com:office:office',
'#default#VML');
}
// Setup default CSS. Only add one style sheet per document
if (!doc.styleSheets['ex_canvas_']) {
var ss = doc.createStyleSheet();
ss.owningElement.id = 'ex_canvas_';
ss.cssText = 'canvas{display:inline-block;overflow:hidden;' +
// default size is 300x150 in Gecko and Opera
'text-align:left;width:300px;height:150px}' +
'g_vml_\\:*{behavior:url(#default#VML)}' +
'g_o_\\:*{behavior:url(#default#VML)}';
}
// find all canvas elements
var els = doc.getElementsByTagName('canvas');
for (var i = 0; i < els.length; i++) {
this.initElement(els[i]);
}
},
/**
* Public initializes a canvas element so that it can be used as canvas
* element from now on. This is called automatically before the page is
* loaded but if you are creating elements using createElement you need to
* make sure this is called on the element.
* @param {HTMLElement} el The canvas element to initialize.
* @return {HTMLElement} the element that was created.
*/
initElement: function(el) {
if (!el.getContext) {
el.getContext = getContext;
// Remove fallback content. There is no way to hide text nodes so we
// just remove all childNodes. We could hide all elements and remove
// text nodes but who really cares about the fallback content.
el.innerHTML = '';
// do not use inline function because that will leak memory
el.attachEvent('onpropertychange', onPropertyChange);
el.attachEvent('onresize', onResize);
var attrs = el.attributes;
if (attrs.width && attrs.width.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setWidth_(attrs.width.nodeValue);
el.style.width = attrs.width.nodeValue + 'px';
} else {
el.width = el.clientWidth;
}
if (attrs.height && attrs.height.specified) {
// TODO: use runtimeStyle and coordsize
// el.getContext().setHeight_(attrs.height.nodeValue);
el.style.height = attrs.height.nodeValue + 'px';
} else {
el.height = el.clientHeight;
}
//el.getContext().setCoordsize_()
}
return el;
}
};
function onPropertyChange(e) {
var el = e.srcElement;
switch (e.propertyName) {
case 'width':
el.style.width = el.attributes.width.nodeValue + 'px';
el.getContext().clearRect();
break;
case 'height':
el.style.height = el.attributes.height.nodeValue + 'px';
el.getContext().clearRect();
break;
}
}
function onResize(e) {
var el = e.srcElement;
if (el.firstChild) {
el.firstChild.style.width = el.clientWidth + 'px';
el.firstChild.style.height = el.clientHeight + 'px';
}
}
G_vmlCanvasManager_.init();
// precompute "00" to "FF"
var dec2hex = [];
for (var i = 0; i < 16; i++) {
for (var j = 0; j < 16; j++) {
dec2hex[i * 16 + j] = i.toString(16) + j.toString(16);
}
}
function createMatrixIdentity() {
return [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
];
}
function matrixMultiply(m1, m2) {
var result = createMatrixIdentity();
for (var x = 0; x < 3; x++) {
for (var y = 0; y < 3; y++) {
var sum = 0;
for (var z = 0; z < 3; z++) {
sum += m1[x][z] * m2[z][y];
}
result[x][y] = sum;
}
}
return result;
}
function copyState(o1, o2) {
o2.fillStyle = o1.fillStyle;
o2.lineCap = o1.lineCap;
o2.lineJoin = o1.lineJoin;
o2.lineWidth = o1.lineWidth;
o2.miterLimit = o1.miterLimit;
o2.shadowBlur = o1.shadowBlur;
o2.shadowColor = o1.shadowColor;
o2.shadowOffsetX = o1.shadowOffsetX;
o2.shadowOffsetY = o1.shadowOffsetY;
o2.strokeStyle = o1.strokeStyle;
o2.globalAlpha = o1.globalAlpha;
o2.arcScaleX_ = o1.arcScaleX_;
o2.arcScaleY_ = o1.arcScaleY_;
o2.lineScale_ = o1.lineScale_;
}
function processStyle(styleString) {
var str, alpha = 1;
styleString = String(styleString);
if (styleString.substring(0, 3) == 'rgb') {
var start = styleString.indexOf('(', 3);
var end = styleString.indexOf(')', start + 1);
var guts = styleString.substring(start + 1, end).split(',');
str = '#';
for (var i = 0; i < 3; i++) {
str += dec2hex[Number(guts[i])];
}
if (guts.length == 4 && styleString.substr(3, 1) == 'a') {
alpha = guts[3];
}
} else {
str = styleString;
}
return {color: str, alpha: alpha};
}
function processLineCap(lineCap) {
switch (lineCap) {
case 'butt':
return 'flat';
case 'round':
return 'round';
case 'square':
default:
return 'square';
}
}
/**
* This class implements CanvasRenderingContext2D interface as described by
* the WHATWG.
* @param {HTMLElement} surfaceElement The element that the 2D context should
* be associated with
*/
function CanvasRenderingContext2D_(surfaceElement) {
this.m_ = createMatrixIdentity();
this.mStack_ = [];
this.aStack_ = [];
this.currentPath_ = [];
// Canvas context properties
this.strokeStyle = '#000';
this.fillStyle = '#000';
this.lineWidth = 1;
this.lineJoin = 'miter';
this.lineCap = 'butt';
this.miterLimit = Z * 1;
this.globalAlpha = 1;
this.canvas = surfaceElement;
var el = surfaceElement.ownerDocument.createElement('div');
el.style.width = surfaceElement.clientWidth + 'px';
el.style.height = surfaceElement.clientHeight + 'px';
el.style.overflow = 'hidden';
el.style.position = 'absolute';
surfaceElement.appendChild(el);
this.element_ = el;
this.arcScaleX_ = 1;
this.arcScaleY_ = 1;
this.lineScale_ = 1;
}
var contextPrototype = CanvasRenderingContext2D_.prototype;
contextPrototype.clearRect = function() {
this.element_.innerHTML = '';
};
contextPrototype.beginPath = function() {
// TODO: Branch current matrix so that save/restore has no effect
// as per safari docs.
this.currentPath_ = [];
};
contextPrototype.moveTo = function(aX, aY) {
var p = this.getCoords_(aX, aY);
this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y});
this.currentX_ = p.x;
this.currentY_ = p.y;
};
contextPrototype.lineTo = function(aX, aY) {
var p = this.getCoords_(aX, aY);
this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y});
this.currentX_ = p.x;
this.currentY_ = p.y;
};
contextPrototype.bezierCurveTo = function(aCP1x, aCP1y,
aCP2x, aCP2y,
aX, aY) {
var p = this.getCoords_(aX, aY);
var cp1 = this.getCoords_(aCP1x, aCP1y);
var cp2 = this.getCoords_(aCP2x, aCP2y);
bezierCurveTo(this, cp1, cp2, p);
};
// Helper function that takes the already fixed cordinates.
function bezierCurveTo(self, cp1, cp2, p) {
self.currentPath_.push({
type: 'bezierCurveTo',
cp1x: cp1.x,
cp1y: cp1.y,
cp2x: cp2.x,
cp2y: cp2.y,
x: p.x,
y: p.y
});
self.currentX_ = p.x;
self.currentY_ = p.y;
}
contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) {
// the following is lifted almost directly from
// http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes
var cp = this.getCoords_(aCPx, aCPy);
var p = this.getCoords_(aX, aY);
var cp1 = {
x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_),
y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_)
};
var cp2 = {
x: cp1.x + (p.x - this.currentX_) / 3.0,
y: cp1.y + (p.y - this.currentY_) / 3.0
};
bezierCurveTo(this, cp1, cp2, p);
};
contextPrototype.arc = function(aX, aY, aRadius,
aStartAngle, aEndAngle, aClockwise) {
aRadius *= Z;
var arcType = aClockwise ? 'at' : 'wa';
var xStart = aX + mc(aStartAngle) * aRadius - Z2;
var yStart = aY + ms(aStartAngle) * aRadius - Z2;
var xEnd = aX + mc(aEndAngle) * aRadius - Z2;
var yEnd = aY + ms(aEndAngle) * aRadius - Z2;
// IE won't render arches drawn counter clockwise if xStart == xEnd.
if (xStart == xEnd && !aClockwise) {
xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something
// that can be represented in binary
}
var p = this.getCoords_(aX, aY);
var pStart = this.getCoords_(xStart, yStart);
var pEnd = this.getCoords_(xEnd, yEnd);
this.currentPath_.push({type: arcType,
x: p.x,
y: p.y,
radius: aRadius,
xStart: pStart.x,
yStart: pStart.y,
xEnd: pEnd.x,
yEnd: pEnd.y});
};
contextPrototype.rect = function(aX, aY, aWidth, aHeight) {
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
};
contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) {
var oldPath = this.currentPath_;
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.stroke();
this.currentPath_ = oldPath;
};
contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) {
var oldPath = this.currentPath_;
this.beginPath();
this.moveTo(aX, aY);
this.lineTo(aX + aWidth, aY);
this.lineTo(aX + aWidth, aY + aHeight);
this.lineTo(aX, aY + aHeight);
this.closePath();
this.fill();
this.currentPath_ = oldPath;
};
contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) {
var gradient = new CanvasGradient_('gradient');
gradient.x0_ = aX0;
gradient.y0_ = aY0;
gradient.x1_ = aX1;
gradient.y1_ = aY1;
return gradient;
};
contextPrototype.createRadialGradient = function(aX0, aY0, aR0,
aX1, aY1, aR1) {
var gradient = new CanvasGradient_('gradientradial');
gradient.x0_ = aX0;
gradient.y0_ = aY0;
gradient.r0_ = aR0;
gradient.x1_ = aX1;
gradient.y1_ = aY1;
gradient.r1_ = aR1;
return gradient;
};
contextPrototype.drawImage = function(image, var_args) {
var dx, dy, dw, dh, sx, sy, sw, sh;
// to find the original width we overide the width and height
var oldRuntimeWidth = image.runtimeStyle.width;
var oldRuntimeHeight = image.runtimeStyle.height;
image.runtimeStyle.width = 'auto';
image.runtimeStyle.height = 'auto';
// get the original size
var w = image.width;
var h = image.height;
// and remove overides
image.runtimeStyle.width = oldRuntimeWidth;
image.runtimeStyle.height = oldRuntimeHeight;
if (arguments.length == 3) {
dx = arguments[1];
dy = arguments[2];
sx = sy = 0;
sw = dw = w;
sh = dh = h;
} else if (arguments.length == 5) {
dx = arguments[1];
dy = arguments[2];
dw = arguments[3];
dh = arguments[4];
sx = sy = 0;
sw = w;
sh = h;
} else if (arguments.length == 9) {
sx = arguments[1];
sy = arguments[2];
sw = arguments[3];
sh = arguments[4];
dx = arguments[5];
dy = arguments[6];
dw = arguments[7];
dh = arguments[8];
} else {
throw Error('Invalid number of arguments');
}
var d = this.getCoords_(dx, dy);
var w2 = sw / 2;
var h2 = sh / 2;
var vmlStr = [];
var W = 10;
var H = 10;
// For some reason that I've now forgotten, using divs didn't work
vmlStr.push(' <g_vml_:group',
' coordsize="', Z * W, ',', Z * H, '"',
' coordorigin="0,0"' ,
' style="width:', W, 'px;height:', H, 'px;position:absolute;');
// If filters are necessary (rotation exists), create them
// filters are bog-slow, so only create them if abbsolutely necessary
// The following check doesn't account for skews (which don't exist
// in the canvas spec (yet) anyway.
if (this.m_[0][0] != 1 || this.m_[0][1]) {
var filter = [];
// Note the 12/21 reversal
filter.push('M11=', this.m_[0][0], ',',
'M12=', this.m_[1][0], ',',
'M21=', this.m_[0][1], ',',
'M22=', this.m_[1][1], ',',
'Dx=', mr(d.x / Z), ',',
'Dy=', mr(d.y / Z), '');
// Bounding box calculation (need to minimize displayed area so that
// filters don't waste time on unused pixels.
var max = d;
var c2 = this.getCoords_(dx + dw, dy);
var c3 = this.getCoords_(dx, dy + dh);
var c4 = this.getCoords_(dx + dw, dy + dh);
max.x = m.max(max.x, c2.x, c3.x, c4.x);
max.y = m.max(max.y, c2.y, c3.y, c4.y);
vmlStr.push('padding:0 ', mr(max.x / Z), 'px ', mr(max.y / Z),
'px 0;filter:progid:DXImageTransform.Microsoft.Matrix(',
filter.join(''), ", sizingmethod='clip');")
} else {
vmlStr.push('top:', mr(d.y / Z), 'px;left:', mr(d.x / Z), 'px;');
}
vmlStr.push(' ">' ,
'<g_vml_:image src="', image.src, '"',
' style="width:', Z * dw, 'px;',
' height:', Z * dh, 'px;"',
' cropleft="', sx / w, '"',
' croptop="', sy / h, '"',
' cropright="', (w - sx - sw) / w, '"',
' cropbottom="', (h - sy - sh) / h, '"',
' />',
'</g_vml_:group>');
this.element_.insertAdjacentHTML('BeforeEnd',
vmlStr.join(''));
};
contextPrototype.stroke = function(aFill) {
var lineStr = [];
var lineOpen = false;
var a = processStyle(aFill ? this.fillStyle : this.strokeStyle);
var color = a.color;
var opacity = a.alpha * this.globalAlpha;
var W = 10;
var H = 10;
lineStr.push('<g_vml_:shape',
' filled="', !!aFill, '"',
' style="position:absolute;width:', W, 'px;height:', H, 'px;"',
' coordorigin="0 0" coordsize="', Z * W, ' ', Z * H, '"',
' stroked="', !aFill, '"',
' path="');
var newSeq = false;
var min = {x: null, y: null};
var max = {x: null, y: null};
for (var i = 0; i < this.currentPath_.length; i++) {
var p = this.currentPath_[i];
var c;
switch (p.type) {
case 'moveTo':
c = p;
lineStr.push(' m ', mr(p.x), ',', mr(p.y));
break;
case 'lineTo':
lineStr.push(' l ', mr(p.x), ',', mr(p.y));
break;
case 'close':
lineStr.push(' x ');
p = null;
break;
case 'bezierCurveTo':
lineStr.push(' c ',
mr(p.cp1x), ',', mr(p.cp1y), ',',
mr(p.cp2x), ',', mr(p.cp2y), ',',
mr(p.x), ',', mr(p.y));
break;
case 'at':
case 'wa':
lineStr.push(' ', p.type, ' ',
mr(p.x - this.arcScaleX_ * p.radius), ',',
mr(p.y - this.arcScaleY_ * p.radius), ' ',
mr(p.x + this.arcScaleX_ * p.radius), ',',
mr(p.y + this.arcScaleY_ * p.radius), ' ',
mr(p.xStart), ',', mr(p.yStart), ' ',
mr(p.xEnd), ',', mr(p.yEnd));
break;
}
// TODO: Following is broken for curves due to
// move to proper paths.
// Figure out dimensions so we can do gradient fills
// properly
if (p) {
if (min.x == null || p.x < min.x) {
min.x = p.x;
}
if (max.x == null || p.x > max.x) {
max.x = p.x;
}
if (min.y == null || p.y < min.y) {
min.y = p.y;
}
if (max.y == null || p.y > max.y) {
max.y = p.y;
}
}
}
lineStr.push(' ">');
if (!aFill) {
var lineWidth = this.lineScale_ * this.lineWidth;
// VML cannot correctly render a line if the width is less than 1px.
// In that case, we dilute the color to make the line look thinner.
if (lineWidth < 1) {
opacity *= lineWidth;
}
lineStr.push(
'<g_vml_:stroke',
' opacity="', opacity, '"',
' joinstyle="', this.lineJoin, '"',
' miterlimit="', this.miterLimit, '"',
' endcap="', processLineCap(this.lineCap), '"',
' weight="', lineWidth, 'px"',
' color="', color, '" />'
);
} else if (typeof this.fillStyle == 'object') {
var fillStyle = this.fillStyle;
var angle = 0;
var focus = {x: 0, y: 0};
// additional offset
var shift = 0;
// scale factor for offset
var expansion = 1;
if (fillStyle.type_ == 'gradient') {
var x0 = fillStyle.x0_ / this.arcScaleX_;
var y0 = fillStyle.y0_ / this.arcScaleY_;
var x1 = fillStyle.x1_ / this.arcScaleX_;
var y1 = fillStyle.y1_ / this.arcScaleY_;
var p0 = this.getCoords_(x0, y0);
var p1 = this.getCoords_(x1, y1);
var dx = p1.x - p0.x;
var dy = p1.y - p0.y;
angle = Math.atan2(dx, dy) * 180 / Math.PI;
// The angle should be a non-negative number.
if (angle < 0) {
angle += 360;
}
// Very small angles produce an unexpected result because they are
// converted to a scientific notation string.
if (angle < 1e-6) {
angle = 0;
}
} else {
var p0 = this.getCoords_(fillStyle.x0_, fillStyle.y0_);
var width = max.x - min.x;
var height = max.y - min.y;
focus = {
x: (p0.x - min.x) / width,
y: (p0.y - min.y) / height
};
width /= this.arcScaleX_ * Z;
height /= this.arcScaleY_ * Z;
var dimension = m.max(width, height);
shift = 2 * fillStyle.r0_ / dimension;
expansion = 2 * fillStyle.r1_ / dimension - shift;
}
// We need to sort the color stops in ascending order by offset,
// otherwise IE won't interpret it correctly.
var stops = fillStyle.colors_;
stops.sort(function(cs1, cs2) {
return cs1.offset - cs2.offset;
});
var length = stops.length;
var color1 = stops[0].color;
var color2 = stops[length - 1].color;
var opacity1 = stops[0].alpha * this.globalAlpha;
var opacity2 = stops[length - 1].alpha * this.globalAlpha;
var colors = [];
for (var i = 0; i < length; i++) {
var stop = stops[i];
colors.push(stop.offset * expansion + shift + ' ' + stop.color);
}
// When colors attribute is used, the meanings of opacity and o:opacity2
// are reversed.
lineStr.push('<g_vml_:fill type="', fillStyle.type_, '"',
' method="none" focus="100%"',
' color="', color1, '"',
' color2="', color2, '"',
' colors="', colors.join(','), '"',
' opacity="', opacity2, '"',
' g_o_:opacity2="', opacity1, '"',
' angle="', angle, '"',
' focusposition="', focus.x, ',', focus.y, '" />');
} else {
lineStr.push('<g_vml_:fill color="', color, '" opacity="', opacity,
'" />');
}
lineStr.push('</g_vml_:shape>');
this.element_.insertAdjacentHTML('beforeEnd', lineStr.join(''));
};
contextPrototype.fill = function() {
this.stroke(true);
}
contextPrototype.closePath = function() {
this.currentPath_.push({type: 'close'});
};
/**
* @private
*/
contextPrototype.getCoords_ = function(aX, aY) {
var m = this.m_;
return {
x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2,
y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2
}
};
contextPrototype.save = function() {
var o = {};
copyState(this, o);
this.aStack_.push(o);
this.mStack_.push(this.m_);
this.m_ = matrixMultiply(createMatrixIdentity(), this.m_);
};
contextPrototype.restore = function() {
copyState(this.aStack_.pop(), this);
this.m_ = this.mStack_.pop();
};
function matrixIsFinite(m) {
for (var j = 0; j < 3; j++) {
for (var k = 0; k < 2; k++) {
if (!isFinite(m[j][k]) || isNaN(m[j][k])) {
return false;
}
}
}
return true;
}
function setM(ctx, m, updateLineScale) {
if (!matrixIsFinite(m)) {
return;
}
ctx.m_ = m;
if (updateLineScale) {
// Get the line scale.
// Determinant of this.m_ means how much the area is enlarged by the
// transformation. So its square root can be used as a scale factor
// for width.
var det = m[0][0] * m[1][1] - m[0][1] * m[1][0];
ctx.lineScale_ = sqrt(abs(det));
}
}
contextPrototype.translate = function(aX, aY) {
var m1 = [
[1, 0, 0],
[0, 1, 0],
[aX, aY, 1]
];
setM(this, matrixMultiply(m1, this.m_), false);
};
contextPrototype.rotate = function(aRot) {
var c = mc(aRot);
var s = ms(aRot);
var m1 = [
[c, s, 0],
[-s, c, 0],
[0, 0, 1]
];
setM(this, matrixMultiply(m1, this.m_), false);
};
contextPrototype.scale = function(aX, aY) {
this.arcScaleX_ *= aX;
this.arcScaleY_ *= aY;
var m1 = [
[aX, 0, 0],
[0, aY, 0],
[0, 0, 1]
];
setM(this, matrixMultiply(m1, this.m_), true);
};
contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) {
var m1 = [
[m11, m12, 0],
[m21, m22, 0],
[dx, dy, 1]
];
setM(this, matrixMultiply(m1, this.m_), true);
};
contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) {
var m = [
[m11, m12, 0],
[m21, m22, 0],
[dx, dy, 1]
];
setM(this, m, true);
};
/******** STUBS ********/
contextPrototype.clip = function() {
// TODO: Implement
};
contextPrototype.arcTo = function() {
// TODO: Implement
};
contextPrototype.createPattern = function() {
return new CanvasPattern_;
};
// Gradient / Pattern Stubs
function CanvasGradient_(aType) {
this.type_ = aType;
this.x0_ = 0;
this.y0_ = 0;
this.r0_ = 0;
this.x1_ = 0;
this.y1_ = 0;
this.r1_ = 0;
this.colors_ = [];
}
CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) {
aColor = processStyle(aColor);
this.colors_.push({offset: aOffset,
color: aColor.color,
alpha: aColor.alpha});
};
function CanvasPattern_() {}
// set up externs
G_vmlCanvasManager = G_vmlCanvasManager_;
CanvasRenderingContext2D = CanvasRenderingContext2D_;
CanvasGradient = CanvasGradient_;
CanvasPattern = CanvasPattern_;
})();
} // if

View file

@ -0,0 +1,77 @@
K 25
svn:wc:ra_dav:version-url
V 34
/svn/!svn/ver/47/tags/m3/testcases
END
gradient.html
K 25
svn:wc:ra_dav:version-url
V 48
/svn/!svn/ver/47/tags/m3/testcases/gradient.html
END
stroke-should-not-close-path.html
K 25
svn:wc:ra_dav:version-url
V 68
/svn/!svn/ver/47/tags/m3/testcases/stroke-should-not-close-path.html
END
gradient2.html
K 25
svn:wc:ra_dav:version-url
V 49
/svn/!svn/ver/47/tags/m3/testcases/gradient2.html
END
saverestorepath.html
K 25
svn:wc:ra_dav:version-url
V 55
/svn/!svn/ver/47/tags/m3/testcases/saverestorepath.html
END
drawimage.html
K 25
svn:wc:ra_dav:version-url
V 49
/svn/!svn/ver/47/tags/m3/testcases/drawimage.html
END
quadraticcurve.html
K 25
svn:wc:ra_dav:version-url
V 54
/svn/!svn/ver/47/tags/m3/testcases/quadraticcurve.html
END
overflow.html
K 25
svn:wc:ra_dav:version-url
V 48
/svn/!svn/ver/47/tags/m3/testcases/overflow.html
END
clearpath.html
K 25
svn:wc:ra_dav:version-url
V 49
/svn/!svn/ver/47/tags/m3/testcases/clearpath.html
END
arc.html
K 25
svn:wc:ra_dav:version-url
V 43
/svn/!svn/ver/47/tags/m3/testcases/arc.html
END
linewidth.html
K 25
svn:wc:ra_dav:version-url
V 49
/svn/!svn/ver/47/tags/m3/testcases/linewidth.html
END
stroke-scale-rotate.html
K 25
svn:wc:ra_dav:version-url
V 59
/svn/!svn/ver/47/tags/m3/testcases/stroke-scale-rotate.html
END
resizing.html
K 25
svn:wc:ra_dav:version-url
V 48
/svn/!svn/ver/47/tags/m3/testcases/resizing.html
END

View file

@ -0,0 +1,436 @@
9
dir
48
https://explorercanvas.googlecode.com/svn/tags/m3/testcases
https://explorercanvas.googlecode.com/svn
2009-03-03T04:08:38.771266Z
45
erik.arvidsson
svn:special svn:externals svn:needs-lock
fd59bba8-8519-0410-9389-e36bf2bdbbd6
gradient.html
file
2009-03-22T18:57:18.641507Z
93783d19cc19d69c4b2818dfb02ee1a4
2008-11-24T01:09:52.534661Z
42
eonics
810
stroke-should-not-close-path.html
file
2009-03-22T18:57:18.643460Z
d0a409b6a982eda0f1baf5c4d4fc0c75
2008-03-02T01:59:00.757253Z
34
eonics
629
gradient2.html
file
2009-03-22T18:57:18.644437Z
f896d57a88dd0efa5387ce04a619a50e
2008-11-24T01:09:52.534661Z
42
eonics
874
saverestorepath.html
file
2009-03-22T18:57:18.646390Z
9b03088f2c8ae15d2e746aa522ead403
2009-01-02T02:19:50.427607Z
44
eonics
858
drawimage.html
file
2009-03-22T18:57:18.647367Z
98b1f3041647da25e91d9c5715f654be
2008-03-02T01:59:00.757253Z
34
eonics
574
quadraticcurve.html
file
2009-03-22T18:57:18.648343Z
6af0dad77029323a3e599773e6072ba5
2008-09-19T04:12:28.526855Z
37
eonics
1052
overflow.html
file
2009-03-22T18:57:18.650296Z
2b45d1ba7b2954231fbcacc56d9cc304
2006-04-14T08:44:46.156934Z
7
eae
has-props
687
clearpath.html
file
2009-03-22T18:57:18.651273Z
e75ee0fc0f1f8361e1d11f6b06c2358d
2009-01-02T02:19:50.427607Z
44
eonics
942
arc.html
file
2009-03-22T18:57:18.654203Z
d85055ddf8e12b4c30a6e71c7a9f526c
2007-04-20T22:26:10.138843Z
18
frenzon
883
linewidth.html
file
2009-03-22T18:57:18.655179Z
ffaa038cb432c8aac88115c524ea5c18
2006-04-08T00:01:24.821143Z
4
eonics
887
stroke-scale-rotate.html
file
2009-03-22T18:57:18.656156Z
cbc02e626a10419d1974c6e646e70a44
2008-03-08T18:56:18.923828Z
35
eonics
1336
resizing.html
file
2009-03-22T18:57:18.657132Z
e25433cd9767b5fb54a00a77ee6e7035
2009-01-02T02:19:50.427607Z
44
eonics
1554

View file

@ -0,0 +1 @@
9

View file

@ -0,0 +1,9 @@
K 13
svn:eol-style
V 6
native
K 13
svn:mime-type
V 9
text/html
END

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<title>Arc Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.beginPath();
ctx.arc(25, 25, 20, 0, Math.PI, false);
ctx.stroke();
ctx.save();
ctx.scale(0.5, 0.5);
ctx.beginPath();
ctx.arc(75, 25, 20, 0, Math.PI * 2, false);
ctx.stroke();
ctx.restore();
ctx.beginPath();
ctx.arc(25, 75, 20, 0, Math.PI, true);
ctx.stroke();
ctx.beginPath();
ctx.arc(75, 75, 20, 0, Math.PI * 2, true);
ctx.stroke();
};
</script>
</head>
<body>
<canvas id=c width=200 height=100></canvas>
<p>This tests that drawing arches work in the same way in different
browsers.</p>
</body>
</html>

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<title>Clear path Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
// Need to test clearRect, strokeRect, fillRect
ctx.beginPath();
ctx.moveTo(0, 50);
ctx.lineTo(50, 100);
ctx.strokeRect(100.5, 125.5, 49, 49);
ctx.lineTo(100, 50);
ctx.fillRect(50, 125, 50, 50);
ctx.lineTo(50, 0);
// clearRect is not correctly implmented in ExCanvas but for this test its
// current behavior is enough.
ctx.clearRect(50, 125, 100, 50);
ctx.lineTo(0, 50);
ctx.stroke();
};
</script>
</head>
<body>
<canvas id=c width=200 height=200></canvas>
<p>This tests the clearing of the path. You should only see a diamond shape
above.</p>
</body>
</html>

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>Overflow Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
var img = document.images[0];
ctx.rotate(Math.PI / 8);
ctx.drawImage(img, 50, 50);
img.style.display = 'none';
};
</script>
</head>
<body>
<img src="../examples/ff.jpg">
<canvas id=c width=200 height=200></canvas>
</body>
</html>

View file

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<title>Gradient Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
var g = ctx.createLinearGradient(0, 0, 300, 0);
g.addColorStop(0, '#000');
g.addColorStop(1 / 7, '#00f');
g.addColorStop(2 / 7, '#0f0');
g.addColorStop(3 / 7, '#0ff');
g.addColorStop(4 / 7, '#f00');
g.addColorStop(5 / 7, '#f0f');
g.addColorStop(6 / 7, '#ff0');
g.addColorStop(1, '#fff');
ctx.fillStyle = g;
ctx.fillRect(0, 0, 300, 200);
};
</script>
</head>
<body>
<canvas id=c width=300 height=200></canvas>
<p>This tests gradients</p>
</body>
</html>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<title>Gradient Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
var g1 = ctx.createLinearGradient(0, 0, 300, 200);
g1.addColorStop(0.0, 'rgba(0, 255, 0, 0.0)');
g1.addColorStop(1.0, 'rgba(0, 255, 0, 1.0)');
var g2 = ctx.createLinearGradient(0, 0, 300, 200);
g2.addColorStop(0.0, 'rgba(0, 255, 0, 1.0)');
// VML Bug
g2.addColorStop(1.0, 'rgba(0, 0, 0, 0.0)');
ctx.fillStyle = g1;
ctx.fillRect(0, 0, 300, 100);
ctx.fillStyle = g2;
ctx.fillRect(0, 100, 300, 100);
};
</script>
</head>
<body>
<canvas id=c width=300 height=200></canvas>
<p>This tests gradients</p>
</body>
</html>

View file

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<title>Line Width Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
for (var i = 0; i < 100; i++) {
ctx.beginPath();
ctx.moveTo(49 + i / 100, i);
ctx.lineTo(49 + i / 100, i + 1);
ctx.closePath();
ctx.stroke();
}
for (var i = 0; i < 100; i++) {
ctx.beginPath();
ctx.moveTo(i, 49 + i / 100);
ctx.lineTo(i + 1, 49 + i / 100);
ctx.closePath();
ctx.stroke();
}
};
</script>
</head>
<body>
<canvas id=c width=100 height=100></canvas>
<p>This tests that lines work in the same way in different browsers when you are
using sub pixel coordinates.</p>
</body>
</html>

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>Overflow Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(-50, -50, 100, 100);
ctx.fillStyle = 'green';
ctx.fillRect(50, 50, 100, 100);
ctx.strokeStyle = 'black';
ctx.strokeRect(0, 0, 100, 100);
};
</script>
</head>
<body>
<canvas id=c width=100 height=100></canvas>
<p>This tests if content gets cropped if painting outside the canvas.</p>
</body>
</html>

View file

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<title>Quadratic Curve Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.save();
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(0, 0, 25, 75);
ctx.quadraticCurveTo(50, 0, 50, 50);
ctx.stroke();
ctx.restore();
// Same with some scaling
ctx.save();
ctx.translate(-56, -24);
ctx.scale(3.5, 1.5);
ctx.strokeStyle = '#ddd';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(0, 0, 25, 75);
ctx.quadraticCurveTo(50, 0, 50, 50);
ctx.stroke();
ctx.restore();
};
</script>
</head>
<body>
<canvas id=c width=200 height=200></canvas>
<p>This tests that drawing quadratic curves work in the same way in different
browsers.</p>
</body>
</html>

View file

@ -0,0 +1,65 @@
<html>
<head>
<title>ExplorerCanvas Text Case</title>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
// Safari is known not to handle resizing well, expect this to
// compare to Firefox
var cv, ctx, size = 80;
var img = new Image();
img.src = "../examples/ff.jpg";
function a() {
cv = document.getElementById("aa");
ctx = cv.getContext("2d");
l();
}
function l() {
size = (size + 1) % 800;
cv.width = Number(size + 200);
cv.height = Number((size + 200) / 2);
// Firefox autoclears the canvas at this point
ctx.save();
ctx.translate(50, 50);
ctx.scale(0.1, 0.1);
ctx.rotate(size/800 * Math.PI*8);
ctx.drawImage(img, 0, -75);
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(cv.width, cv.height);
ctx.moveTo(20, 20);
ctx.lineTo(80, 20);
ctx.lineTo(80, 80);
ctx.lineTo(20, 80);
ctx.stroke();
ctx.closePath();
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.scale(size / 200, size / 200);
ctx.arc(100, 50, 20, 0, Math.PI, true);
ctx.fill();
ctx.restore();
setTimeout(l, 50);
}
</script>
<style>
canvas {
background-color:#eee;
}
</style>
</head>
<body onload="a();">
<canvas id="aa" width="200" height="200">Fallback <b>content</b> markup</canvas>
</body>
</html>

View file

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<title>Save/restore path Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
// Need to test clearRect, strokeRect, fillRect
ctx.beginPath();
ctx.moveTo(0, 50);
ctx.lineTo(50, 100);
ctx.save();
ctx.lineTo(100, 50);
ctx.restore();
ctx.save();
ctx.lineTo(50, 0);
ctx.restore();
ctx.save();
ctx.lineTo(0, 50);
ctx.restore();
ctx.stroke();
};
</script>
</head>
<body>
<canvas id=c width=200 height=200></canvas>
<p>This tests ensures that save/restore does not do anything to the current
path. You should see a diamond shape above.</p>
</body>
</html>

View file

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<title>Stroke Scale</title>
<style>
body {
text-align: center
}
canvas {
background: #eee;
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
// draw a star
function drawStar (ctx, r){
ctx.save();
ctx.beginPath();
ctx.rotate(-Math.PI / 10);
ctx.scale(r, r);
ctx.moveTo(1, 0);
ctx.lineWidth = ctx.lineWidth / r;
for (var i = 0; i < 9; i++) {
ctx.rotate(Math.PI / 5);
if (i % 2 == 0) {
ctx.lineTo(0.3819653016466596, 0);
} else {
ctx.lineTo(1, 0);
}
}
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
}
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.save();
ctx.translate(100.5, 100);
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(50, 0);
ctx.scale(1, 2);
ctx.rotate(Math.PI / 2);
ctx.lineTo(25, -50)
ctx.rotate(Math.PI / 2);
ctx.lineTo(0, -25)
ctx.scale(1, 2);
ctx.closePath();
ctx.stroke();
ctx.restore();
ctx.translate(50, 50);
ctx.fillStyle = 'white';
ctx.strokeStyle = 'blue';
drawStar(ctx, 20);
};
</script>
</head>
<body>
<canvas id=c width=500 height=500></canvas>
</body>
</html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#ccc";
ctx.strokeStyle = "#000";
ctx.beginPath();
ctx.moveTo(30, 30);
ctx.lineTo(150, 150);
ctx.bezierCurveTo(60, 70, 60, 70, 70, 150);
ctx.fill();
ctx.stroke();
};
</script>
</head>
<body>
<canvas id=c width=200 height=200></canvas>
</body>
</html>

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<title>Arc Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.beginPath();
ctx.arc(25, 25, 20, 0, Math.PI, false);
ctx.stroke();
ctx.save();
ctx.scale(0.5, 0.5);
ctx.beginPath();
ctx.arc(75, 25, 20, 0, Math.PI * 2, false);
ctx.stroke();
ctx.restore();
ctx.beginPath();
ctx.arc(25, 75, 20, 0, Math.PI, true);
ctx.stroke();
ctx.beginPath();
ctx.arc(75, 75, 20, 0, Math.PI * 2, true);
ctx.stroke();
};
</script>
</head>
<body>
<canvas id=c width=200 height=100></canvas>
<p>This tests that drawing arches work in the same way in different
browsers.</p>
</body>
</html>

View file

@ -0,0 +1,49 @@
<!DOCTYPE html>
<html>
<head>
<title>Clear path Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
// Need to test clearRect, strokeRect, fillRect
ctx.beginPath();
ctx.moveTo(0, 50);
ctx.lineTo(50, 100);
ctx.strokeRect(100.5, 125.5, 49, 49);
ctx.lineTo(100, 50);
ctx.fillRect(50, 125, 50, 50);
ctx.lineTo(50, 0);
// clearRect is not correctly implmented in ExCanvas but for this test its
// current behavior is enough.
ctx.clearRect(50, 125, 100, 50);
ctx.lineTo(0, 50);
ctx.stroke();
};
</script>
</head>
<body>
<canvas id=c width=200 height=200></canvas>
<p>This tests the clearing of the path. You should only see a diamond shape
above.</p>
</body>
</html>

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>Overflow Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
var img = document.images[0];
ctx.rotate(Math.PI / 8);
ctx.drawImage(img, 50, 50);
img.style.display = 'none';
};
</script>
</head>
<body>
<img src="../examples/ff.jpg">
<canvas id=c width=200 height=200></canvas>
</body>
</html>

View file

@ -0,0 +1,39 @@
<!DOCTYPE html>
<html>
<head>
<title>Gradient Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
var g = ctx.createLinearGradient(0, 0, 300, 0);
g.addColorStop(0, '#000');
g.addColorStop(1 / 7, '#00f');
g.addColorStop(2 / 7, '#0f0');
g.addColorStop(3 / 7, '#0ff');
g.addColorStop(4 / 7, '#f00');
g.addColorStop(5 / 7, '#f0f');
g.addColorStop(6 / 7, '#ff0');
g.addColorStop(1, '#fff');
ctx.fillStyle = g;
ctx.fillRect(0, 0, 300, 200);
};
</script>
</head>
<body>
<canvas id=c width=300 height=200></canvas>
<p>This tests gradients</p>
</body>
</html>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<head>
<title>Gradient Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
var g1 = ctx.createLinearGradient(0, 0, 300, 200);
g1.addColorStop(0.0, 'rgba(0, 255, 0, 0.0)');
g1.addColorStop(1.0, 'rgba(0, 255, 0, 1.0)');
var g2 = ctx.createLinearGradient(0, 0, 300, 200);
g2.addColorStop(0.0, 'rgba(0, 255, 0, 1.0)');
// VML Bug
g2.addColorStop(1.0, 'rgba(0, 0, 0, 0.0)');
ctx.fillStyle = g1;
ctx.fillRect(0, 0, 300, 100);
ctx.fillStyle = g2;
ctx.fillRect(0, 100, 300, 100);
};
</script>
</head>
<body>
<canvas id=c width=300 height=200></canvas>
<p>This tests gradients</p>
</body>
</html>

View file

@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<title>Line Width Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
for (var i = 0; i < 100; i++) {
ctx.beginPath();
ctx.moveTo(49 + i / 100, i);
ctx.lineTo(49 + i / 100, i + 1);
ctx.closePath();
ctx.stroke();
}
for (var i = 0; i < 100; i++) {
ctx.beginPath();
ctx.moveTo(i, 49 + i / 100);
ctx.lineTo(i + 1, 49 + i / 100);
ctx.closePath();
ctx.stroke();
}
};
</script>
</head>
<body>
<canvas id=c width=100 height=100></canvas>
<p>This tests that lines work in the same way in different browsers when you are
using sub pixel coordinates.</p>
</body>
</html>

View file

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html>
<head>
<title>Overflow Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.fillStyle = 'blue';
ctx.fillRect(-50, -50, 100, 100);
ctx.fillStyle = 'green';
ctx.fillRect(50, 50, 100, 100);
ctx.strokeStyle = 'black';
ctx.strokeRect(0, 0, 100, 100);
};
</script>
</head>
<body>
<canvas id=c width=100 height=100></canvas>
<p>This tests if content gets cropped if painting outside the canvas.</p>
</body>
</html>

View file

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<title>Quadratic Curve Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.save();
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(0, 0, 25, 75);
ctx.quadraticCurveTo(50, 0, 50, 50);
ctx.stroke();
ctx.restore();
// Same with some scaling
ctx.save();
ctx.translate(-56, -24);
ctx.scale(3.5, 1.5);
ctx.strokeStyle = '#ddd';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.quadraticCurveTo(0, 0, 25, 75);
ctx.quadraticCurveTo(50, 0, 50, 50);
ctx.stroke();
ctx.restore();
};
</script>
</head>
<body>
<canvas id=c width=200 height=200></canvas>
<p>This tests that drawing quadratic curves work in the same way in different
browsers.</p>
</body>
</html>

View file

@ -0,0 +1,65 @@
<html>
<head>
<title>ExplorerCanvas Text Case</title>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
// Safari is known not to handle resizing well, expect this to
// compare to Firefox
var cv, ctx, size = 80;
var img = new Image();
img.src = "../examples/ff.jpg";
function a() {
cv = document.getElementById("aa");
ctx = cv.getContext("2d");
l();
}
function l() {
size = (size + 1) % 800;
cv.width = Number(size + 200);
cv.height = Number((size + 200) / 2);
// Firefox autoclears the canvas at this point
ctx.save();
ctx.translate(50, 50);
ctx.scale(0.1, 0.1);
ctx.rotate(size/800 * Math.PI*8);
ctx.drawImage(img, 0, -75);
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(cv.width, cv.height);
ctx.moveTo(20, 20);
ctx.lineTo(80, 20);
ctx.lineTo(80, 80);
ctx.lineTo(20, 80);
ctx.stroke();
ctx.closePath();
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.scale(size / 200, size / 200);
ctx.arc(100, 50, 20, 0, Math.PI, true);
ctx.fill();
ctx.restore();
setTimeout(l, 50);
}
</script>
<style>
canvas {
background-color:#eee;
}
</style>
</head>
<body onload="a();">
<canvas id="aa" width="200" height="200">Fallback <b>content</b> markup</canvas>
</body>
</html>

View file

@ -0,0 +1,48 @@
<!DOCTYPE html>
<html>
<head>
<title>Save/restore path Test</title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
// Need to test clearRect, strokeRect, fillRect
ctx.beginPath();
ctx.moveTo(0, 50);
ctx.lineTo(50, 100);
ctx.save();
ctx.lineTo(100, 50);
ctx.restore();
ctx.save();
ctx.lineTo(50, 0);
ctx.restore();
ctx.save();
ctx.lineTo(0, 50);
ctx.restore();
ctx.stroke();
};
</script>
</head>
<body>
<canvas id=c width=200 height=200></canvas>
<p>This tests ensures that save/restore does not do anything to the current
path. You should see a diamond shape above.</p>
</body>
</html>

View file

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html>
<head>
<title>Stroke Scale</title>
<style>
body {
text-align: center
}
canvas {
background: #eee;
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
// draw a star
function drawStar (ctx, r){
ctx.save();
ctx.beginPath();
ctx.rotate(-Math.PI / 10);
ctx.scale(r, r);
ctx.moveTo(1, 0);
ctx.lineWidth = ctx.lineWidth / r;
for (var i = 0; i < 9; i++) {
ctx.rotate(Math.PI / 5);
if (i % 2 == 0) {
ctx.lineTo(0.3819653016466596, 0);
} else {
ctx.lineTo(1, 0);
}
}
ctx.closePath();
ctx.fill();
ctx.stroke();
ctx.restore();
}
window.onload = function() {
var ctx = document.getElementById('c').getContext('2d');
ctx.save();
ctx.translate(100.5, 100);
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(50, 0);
ctx.scale(1, 2);
ctx.rotate(Math.PI / 2);
ctx.lineTo(25, -50)
ctx.rotate(Math.PI / 2);
ctx.lineTo(0, -25)
ctx.scale(1, 2);
ctx.closePath();
ctx.stroke();
ctx.restore();
ctx.translate(50, 50);
ctx.fillStyle = 'white';
ctx.strokeStyle = 'blue';
drawStar(ctx, 20);
};
</script>
</head>
<body>
<canvas id=c width=500 height=500></canvas>
</body>
</html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<style>
body {
text-align: center
}
</style>
<!--[if IE]><script type="text/javascript" src="../excanvas.js"></script><![endif]-->
<script>
window.onload = function() {
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#ccc";
ctx.strokeStyle = "#000";
ctx.beginPath();
ctx.moveTo(30, 30);
ctx.lineTo(150, 150);
ctx.bezierCurveTo(60, 70, 60, 70, 70, 150);
ctx.fill();
ctx.stroke();
};
</script>
</head>
<body>
<canvas id=c width=200 height=200></canvas>
</body>
</html>

View file

@ -0,0 +1,14 @@
/**
* jQuery DrawBox Plug-In 1.0
*
* http://github.com/crowdsavings/drawbox
* http://plugins.jquery.com/project/drawbox
*
* Author: Josh Sherman <josh@crowdsavings.com>
* Copyright (c) 2010 CrowdSavings.com, LLC
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
(function(a){a.fn.extend({drawbox:function(d){d=a.extend({lineWidth:1,lineCap:"butt",lineJoin:"miter",miterLimit:10,strokeStyle:"black",fillStyle:"none",shadowOffsetX:0,shadowOffsetY:0,shadowBlur:0,shadowColor:"none",colorSelector:false,colors:["black","red","orange","yellow","green","blue","indigo","violet"],showClear:true,clearLabel:"Clear Canvas",clearStyle:"button"},d);return this.each(function(){if(this.nodeName=="CANVAS"||navigator.userAgent.indexOf("MSIE")!=-1){a(this).css("cursor","pointer"); a(this).attr("onclick","function onclick(event) { void 1; }");if(this.getContext){var l=this,b=this.getContext("2d"),e=a(this).attr("id");a(this).after('<div id="'+e+'-controls" style="width:'+a(this).width()+'px"></div>');b.underInteractionEnabled=true;b.lineWidth=d.lineWidth;b.lineCap=d.lineCap;b.lineJoin=d.lineJoin;b.miterLimit=d.miterLimit;b.strokeStyle=d.strokeStyle;b.fillStyle=d.fillStyle;b.shadowOffsetX=d.shadowOffsetX;b.shadowOffsetY=d.shadowOffsetY;b.shadowBlur=d.shadowBlur;b.shadowColor= d.shadowColor;if(d.colorSelector==true){var j="";for(i in d.colors){var u=d.colors[i];if(i==0)b.strokeStyle=u;j=j+'<div style="height:16px;width:16px;background-color:'+u+";margin:2px;float:left;border:2px solid "+(i==0?"#000":"transparent")+'"'+(i==0?' class="selected"':"")+"></div>"}a("#"+e+"-controls").append('<div style="float:left" id="'+e+'-colors">'+j+"</div>")}if(d.showClear==true){j=d.clearStyle=="link"?"div":"button";a("#"+e+"-controls").append("<"+j+' id="'+e+'-clear" style="float:right">'+ d.clearLabel+"</"+j+'><br style="clear:both" />');clear=true}var m=e+"-data";a(this).after('<input type="hidden" id="'+m+'" name="'+m+'" />');var p=false,q=a("#"+e).height(),r=a("#"+e).width(),f="",k=false,s=false,g=false,h=false;a(document).mousedown(function(c){v(c)});a(document).mousemove(function(c){w(c)});a(document).mouseup(function(){t()});a(document).bind("touchstart",function(c){v(c)});a(document).bind("touchmove",function(c){w(c)});a(document).bind("touchend",function(){t()});a(document).bind("touchcancel", function(){t()});a("#"+e+"-colors div").click(function(){a("#"+e+"-controls div").css("borderColor","transparent").removeClass("selected");a(this).addClass("selected");a(this).css("borderColor","#000")});a("#"+e+"-clear").click(function(){b.save();b.beginPath();b.closePath();b.restore();b.clearRect(0,0,a(l).width(),a(l).height());a("#"+m).val("")});var x=function(c){if(typeof event!="undefined"&&typeof event.touches!="undefined")c=event.touches.item(0);else{a(document).scrollLeft();a(document).scrollTop()}if(g!= false)s=g;g=c.pageX-a(l).position().left;h=c.pageY-a(l).position().top;return c},n=function(c){if(c!="stop"){if(c=="start"){s=k=false;b.beginPath();b.moveTo(g,h);f='<polyline points="'}else{if(s==false){g+=1;h+=1}b.lineTo(g,h)}b.stroke();if(f.length>0&&f.substring(f.length-1)!='"')f+=" ";f=f+g+","+h;q=a("#"+e).height();r=a("#"+e).width();if(g>0&&g<=r&&h>0&&h<=q)k=true}else{n("move");if(k==true){f=f+'" style="fill:'+d.fillStyle+";stroke:"+b.strokeStyle+";stroke-width:"+b.lineWidth+'" /></svg>';c=a("#"+ m);var o=c.val();if(o=="")o='<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="'+r+'" height="'+q+'" version="1.1" xmlns="http://www.w3.org/2000/svg"></svg>';c.val(o.substring(0,o.length-6)+f)}}},v=function(c){k==true&&c.preventDefault();p=true;x(c);b.strokeStyle=a("#"+e+"-colors div.selected").css("backgroundColor");n("start")},w=function(c){k==true&&c.preventDefault();if(p==true){x(c);n("move")}return false}, t=function(){p=false;n("stop")}}else alert("Your browser does not support <canvas>")}else alert(".drawbox() only works on <canvas> elements")})}})})(jQuery);

304
jquery.drawbox.js Normal file
View file

@ -0,0 +1,304 @@
/**
* jQuery DrawBox Plug-In 1.0
*
* http://github.com/crowdsavings/drawbox
* http://plugins.jquery.com/project/drawbox
*
* Author: Josh Sherman <josh@crowdsavings.com>
* Copyright (c) 2010 CrowdSavings.com, LLC
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
(function($)
{
$.fn.extend(
{
drawbox: function(options)
{
// Default options
var defaults = {
// Canvas properties
lineWidth: 1.0,
lineCap: 'butt',
lineJoin: 'miter',
miterLimit: 10,
strokeStyle: 'black',
fillStyle: 'none',
shadowOffsetX: 0.0,
shadowOffsetY: 0.0,
shadowBlur: 0.0,
shadowColor: 'none',
// Color selector options
colorSelector: false,
colors: [ 'black', 'red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet' ],
// Clearing options
showClear: true,
clearLabel: 'Clear Canvas',
clearStyle: 'button' // or 'link'
}
options = $.extend(defaults, options);
return this.each(function()
{
// The IE check is because explorercanvas swaps out the canvas element
if (this.nodeName == 'CANVAS' || navigator.userAgent.indexOf('MSIE') != -1)
{
$(this).css('cursor', 'pointer');
$(this).attr('onclick', 'function onclick(event) { void 1; }');
if (this.getContext)
{
var canvas = this;
var context = this.getContext('2d');
var id = $(this).attr('id');
$(this).after('<div id="' + id + '-controls" style="width:' + $(this).width() + 'px"></div>');
context.underInteractionEnabled = true;
// Overrides with passed options
context.lineWidth = options.lineWidth;
context.lineCap = options.lineCap;
context.lineJoin = options.lineJoin;
context.miterLimit = options.miterLimit;
context.strokeStyle = options.strokeStyle;
context.fillStyle = options.fillStyle;
context.shadowOffsetX = options.shadowOffsetX;
context.shadowOffsetY = options.shadowOffsetY;
context.shadowBlur = options.shadowBlur;
context.shadowColor = options.shadowColor;
// Adds the color selector
if (options.colorSelector == true)
{
var color_selector = '';
for (i in options.colors)
{
var color = options.colors[i];
if (i == 0)
{
context.strokeStyle = color
}
color_selector = color_selector + '<div style="height:16px;width:16px;background-color:' + color + ';margin:2px;float:left;border:2px solid ' + (i == 0 ? '#000' : 'transparent') + '"' + (i == 0 ? ' class="selected"' : '') + '></div>';
}
$('#' + id + '-controls').append('<div style="float:left" id="' + id + '-colors">' + color_selector + '</div>');
}
// Adds the clear button / link
if (options.showClear == true)
{
var clear_tag = (options.clearStyle == 'link' ? 'div' : 'button');
$('#' + id + '-controls').append('<' + clear_tag + ' id="' + id + '-clear" style="float:right">' + options.clearLabel + '</' + clear_tag + '><br style="clear:both" />');
clear = true;
}
var data_input = id + '-data';
$(this).after('<input type="hidden" id="' + data_input + '" name="' + data_input + '" />');
// Defines all our tracking variables
var drawing = false;
var height = $('#' + id).height();
var width = $('#' + id).width();
var svg_path = '';
var scrollLeft = 0;
var scrollTop = 0;
var inside = false
var prevX = false;
var prevY = false;
var x = false;
var y = false;
// Mouse events
$(document).mousedown(function(e) { drawingStart(e); });
$(document).mousemove(function(e) { drawingMove(e); });
$(document).mouseup( function() { drawingStop(); });
// Touch events
$(document).bind('touchstart', function(e) { drawingStart(e); });
$(document).bind('touchmove', function(e) { drawingMove(e); });
$(document).bind('touchend', function() { drawingStop(); });
$(document).bind('touchcancel', function() { drawingStop(); });
// Changing colors
$('#' + id + '-colors div').click(function(e)
{
$('#' + id + '-controls div').css('borderColor', 'transparent').removeClass('selected');
$(this).addClass('selected');
$(this).css('borderColor', '#000');
});
// Clearing the canvas
$('#' + id + '-clear').click(function(e)
{
context.save();
context.beginPath();
context.closePath();
context.restore();
context.clearRect(0, 0, $(canvas).width(), $(canvas).height());
$('#' + data_input).val('');
});
function getTouch(e)
{
// iPhone/iPad/iPod uses event.touches and not the passed event
if (typeof(event) != "undefined" && typeof(event.touches) != "undefined")
{
e = event.touches.item(0);
scrollLeft = document.body.scrollLeft;
scrollTop = document.body.scrollTop;
}
else
{
scrollLeft = $(document).scrollLeft();
scrollTop = $(document).scrollTop();
}
// Tracks last position to handle dots (as opposed to lines)
if (x != false)
{
prevX = x;
prevY = y;
}
// Calculates the X and Y values
x = e.pageX - $(canvas).position().left;
y = e.pageY - $(canvas).position().top;
return e;
}
function draw(type)
{
if (type != 'stop')
{
if (type == 'start')
{
inside = false;
prevX = false;
prevY = false;
context.beginPath();
context.moveTo(x, y);
svg_path = '<polyline points="';
}
else
{
// If there's no previous increment since it's a .
if (prevX == false)
{
x = x + 1;
y = y + 1;
}
context.lineTo(x, y);
}
context.stroke();
if (svg_path.length > 0 && svg_path.substring(svg_path.length - 1) != '"')
{
svg_path = svg_path + ' ';
}
svg_path = svg_path + x + ',' + y;
height = $('#' + id).height();
width = $('#' + id).width();
if ((x > 0 && x <= width) && (y > 0 && y <= height))
{
inside = true;
}
}
else
{
draw('move');
if (inside == true)
{
// Closes the polyline (with style info) and adds the closing svg tag
svg_path = svg_path + '" style="fill:' + options.fillStyle + ';stroke:' + context.strokeStyle + ';stroke-width:' + context.lineWidth + '" /></svg>';
var element = $('#' + data_input);
var svg_data = element.val();
// Adds the opening and closing SVG tags
if (svg_data == '')
{
svg_data = '<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="' + width + '" height="' + height + '" version="1.1" xmlns="http://www.w3.org/2000/svg"></svg>';
}
// Appends the recorded path
element.val(svg_data.substring(0, svg_data.length - 6) + svg_path);
}
}
}
function drawingStart(e)
{
// Prevent the default action (scrolling) from occurring
if (inside == true)
{
e.preventDefault();
}
drawing = true;
e = getTouch(e);
context.strokeStyle = $('#' + id + '-colors div.selected').css('backgroundColor');
draw('start');
}
function drawingMove(e)
{
// Prevent the default action (scrolling) from occurring
if (inside == true)
{
e.preventDefault();
}
if (drawing == true)
{
e = getTouch(e);
draw('move');
}
return false;
}
function drawingStop()
{
drawing = false;
// Draws one last line so we can draw dots (e.g. i)
draw('stop');
}
}
else
{
alert('Your browser does not support <canvas>');
}
}
else
{
alert('.drawbox() only works on <canvas> elements');
}
});
}
});
})(jQuery);