Archiv der Kategorie ‘canvas‘

 
 

New Projects

I have a few new personal projects up and running on github. Have a look:

https://github.com/ZevanRosser

Zapp
Simplified object creation, custom events and deep linking/routing

jquery.select-all
a different kind of javascript templating

OnionSkin
Canvas based animation tool inspired by Flash’s onion skinning

I may create a short video soon that walks through each of these projects.

Image Map & Canvas

I had an interesting idea a few days…. make a canvas element, put a transparent gif over it, create an image map with some shapes and then read the coords property of the area elements to draw to the canvas. I whipped it up a day or two ago and am posting it now at 2 in the morning.

click here if you don’t know what an image map is…

Here is the slightly boring result, just roll over the shapes… code is below:

This is just an interesting experiment. Having mouse events in canvas is not necessary more most of the time. This code is a bit rough, but it’s a solid proof of concept:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
<!DOCTYPE html> 
<html> 
  <head> 
    <meta charset="utf-8" />
    <title>Canvas Map</title> 
    <script src="http://code.jquery.com/jquery-1.5.1.min.js"></script>
 
    <script>
      $(function(){
 
        var TWO_PI = Math.PI * 2;
 
        var map = $("#map");
        var areas = $("#areas");
        var canvas = $("#canvas")[0];
        canvas.width = 500;
        canvas.height = 500;
        var c = canvas.getContext("2d");
 
        $.fn.render = function(){ 
          this.data.apply(this, arguments);
          render();
        }
 
        function clear(){    
          c.fillStyle = "black";
          c.fillRect(0, 0, canvas.width, canvas.height);
        }
 
        // create a rectangle
        $('<area />', {
          shape : "rect",
          coords : "10, 10, 100, 100",
          href :  "#",
          alt : "rect"
        }).data({
 
          fillStyle: "red",
          strokeStyle : "white"
 
        }).mouseenter(function(){
          $(this).render("fillStyle", "orange");
 
        }).mouseleave(function(){
          $(this).render("fillStyle", "red");
 
        }).click(function(){
          alert("hello");
        }).appendTo(areas);
 
 
        // create a circle
        $('<area />', {
          shape : "circle",
          coords : "100, 300, 50",
          href :  "#",
          alt : "circ"
        }).data({
 
          fillStyle: "#a3bcd6",
          strokeStyle : "white",
          lineWidth : 5
 
        }).mouseenter(function(){
          $(this).render("strokeStyle", "red");
 
        }).mouseleave(function(){
          $(this).render("strokeStyle", "white");
 
        }).appendTo(areas);
 
        // create a poly
        $('<area />', {
          shape : "poly",
          coords : "300, 200, 350,250, 250, 350, 200, 250, 260, 280",
          href :  "#",
          alt : "poly"
        }).data({
 
          fillStyle: "#bf9c82",
          strokeStyle : "#ebce59",
          lineWidth : 2
 
        }).mouseenter(function(){
          $(this).render({strokeStyle: "#ede1b0",
                          fillStyle : "white"});
          render();
        }).mouseleave(function(){
          $(this).render({strokeStyle: "#ebce59",
                          fillStyle : "bf9c82"});
 
        }).appendTo(areas);
 
 
        render();
 
 
        function setStyle(fillStyle, strokeStyle, lineWidth){
          if (fillStyle){
            c.fillStyle = fillStyle; 
 
          }
          if (strokeStyle){
            if (lineWidth){
              c.lineWidth = lineWidth; 
            }
            c.strokeStyle = strokeStyle;   
          }
        }
 
        function fillStroke(fillStyle, strokeStyle){
          if (fillStyle) c.fill();
          if (strokeStyle) c.stroke();
        }
 
        function render(noClear){
          if (!noClear){
            clear();
          }
 
          areas.children().each(function(i){
            var area = $(this);
            var shape = area.attr("shape");
            var coords = area.attr("coords").split(",");
            var fillStyle = area.data("fillStyle");
            var strokeStyle = area.data("strokeStyle");
            var lineWidth = area.data("lineWidth");
 
            if (shape == "rect"){
 
              if (fillStyle){
                c.fillStyle = fillStyle; 
                c.fillRect(coords[0], coords[1], coords[2] – coords[0], coords[3] – coords[1]);
              }
              if (strokeStyle){
                if (lineWidth){
                  c.lineWidth = lineWidth; 
                }
                c.strokeStyle = strokeStyle; 
                c.strokeRect(coords[0], coords[1], coords[2] – coords[0], coords[3] – coords[1]);
              }
 
            }else if (shape == "circle"){
 
              setStyle(fillStyle, strokeStyle, lineWidth);
 
              c.beginPath();
              c.arc(coords[0], coords[1], coords[2], 0, TWO_PI, false);
              c.closePath();
 
              fillStroke(fillStyle, strokeStyle);
 
            }else if (shape == "poly"){
 
              if (fillStyle){
                c.fillStyle = fillStyle; 
 
              }
              if (strokeStyle){
                if (lineWidth){
                  c.lineWidth = lineWidth; 
                }
                c.strokeStyle = strokeStyle;   
              }
 
 
              c.beginPath();
              var leng = coords.length;
              c.moveTo(coords[0], coords[1]);
              for (var i = 2; i < leng; i+=2){
                c.lineTo(coords[i], coords[i+1]); 
              }
              c.closePath();
 
              fillStroke(fillStyle, strokeStyle);
 
            }
 
            c.lineWidth = 1;
          });
        }
      });
    </script>
    <style>
      .canvasMap{
        position : absolute;
        top : 0px;
        left : 0px;
        width : 500px;
        height : 500px;
      }
    </style>
  </head> 
 
  <body> 
 
    <div id="container">
      <map name="map">
        <div id="areas"> 
        </div>
      </map>
      <canvas class="canvasMap" id="canvas"></canvas>
      <img id="image" class="canvasMap" src="trans.gif" usemap="#map"/>
 
    </div>
 
  </body> 
</html>

Canvas and Raphael

In this post I’m going to talk about Canvas and Raphael and some of the important differences between them. Last year at some point I discovered Raphael… it’s an amazing drawing library that renders SVG or VML (for IE). One of the issues with canvas is that it doesn’t run in earlier versions of IE. A solution for this problem is excanvas, which will turn your canvas code into VML when it runs in IE – I used it for a few things and it works but has some weird problems. There are some really important differences between SVG/VML here are a few off the top of my head:

I’m just going to say SVG instead of SVG/VML all the time, but when I say SVG I mean both…

Mouse Events
– canvas doesn’t have these built in so you have to write your own like in processing.
I’ve been working on a library for this that I’ll release at some point in the next few weeks

– SVG elements are part of the DOM so regular mouse events work the same way as they would on a div.

Pixels vs Vectors
– working with canvas is like painting, once you draw something, it’s on the canvas and if you want to erase it you have to draw over it.
This is great for drawing programs and photo-manipulation, but can be tricky for UI stuff and games (if you don’t just wipe the whole screen all the time which can be CPU intensive). Also, since we’re dealing with pixels, you can’t easily scale your canvas without losing image quality (there are work arounds for this of course, I just mean by default)

– with SVG, since we’re in vector graphics world, renderer looks at each element and figures out how to draw everything for you so you don’t need to worry about erasing the background every frame (you also have control of drawing order since the renderer just uses the order of elements in the DOM to determine how it draws things) – and SVG is obviously scalable…
This is great for UI elements, graphs and simple games, but can be tricky/useless for certain types of drawing programs and photo manipulation. Scaling graphics is easy, but Raphael doesn’t implement it exactly, so I wrote a helper script that allows you to easily scale your Raphael drawing,

Saving Images
– it’s very easy to save image files of your canvas element

– as far as I know you can’t rasterize SVG to an image file like jpg or png without the use of server-side code
You can pretty easily draw your SVG to a canvas element and save it that way (have a post about this in the pipeline)

Transform Matrices
– canvas has these built in with it’s save() and restore() functions
Among countless other things… this allows you to create parent-child relationships between elements.

– These exist in SVG too, but Raphael doesn’t implement them in a standard and familiar way so you have to hack it

Speed
– I haven’t done enough testing in this area, but there are a few things worth mentioning. On mobile devices SVG is noticeably smoother (at least on the iPhone) – I’ve recently been showing people my web app demos for class and some developers have asked me how I get things to run so smoothly (answer = Raphael and careful coding). If you have a complex vector graphic in SVG and your moving it around, it will run slowly, if you rasterize that same graphic and move it in the canvas it will run smoothly. You could of course just rasterize it and move it around in SVG as a image. If you are dynamically adding many static elements to your drawing during runtime, canvas will never slow down because your just changing pixel values, if you are doing this with SVG your increasing the number of DOM elements as well as the number of elements that need to go through the render pipeline – so SVG will eventually choke. One thing that has been floating around in my head recently is the idea of doing a Raphael/Canvas drawing app where you draw your shapes with SVG and then they get painted onto the canvas – may whip that up at some point.

There is a lot more to talk about here, things like text rendering and the advantages of DOM other than simple mouse events. Maybe in a later post….


Den ganzen Beitrag lesen…