diff --git a/screencasts/svgopen2010/index.html b/screencasts/svgopen2010/index.html new file mode 100644 index 00000000..6fcfd526 --- /dev/null +++ b/screencasts/svgopen2010/index.html @@ -0,0 +1,296 @@ + + + + + + + + + + SVG-edit, Pavol Rusnák, SVG Open 2010, Paris + + + + + +
+
+
+ +
+
+

SVG-edit

+

logo

+

Pavol Rusnák

+

SVG Open 2010, Paris

+
+
+ +
+
+
+

SVG-edit is ...

+
+
    +
  • a web-based, JavaScript-driven SVG editor that works in any modern browser
  • +
  • not a full replacement for Inkscape
  • +
  • licensed under open source license (Apache License 2.0)
  • +
  • platform for other projects which need to edit SVG documents
  • +
  • pushing browsers to find their limits
  • +
  • always up-to-date
  • +
+
+
+ +
+
+
+

History: version 1.0 (13th Feb 2009)

+
+
    +
  • draw path, line, freehand-circle, rectangle
  • +
  • clear drawn image
  • +
  • delete element
  • +
  • save image
  • +
+

_

+
+
+ +
+
+
+

History: version 2.0 (3rd June 2009)

+
+
    +
  • draw ellipse, square
  • +
  • change stroke-dasharray (line style)
  • +
  • rearranged whole code to OOP
  • +
  • GUI enhancement
  • +
+

_

+
+
+ +
+
+
+

History: version 2.1 (17th June 2009)

+
+
    +
  • tooltips added to all UI elements
  • +
  • edit of fill opacity, stroke opacity, group opacity
  • +
  • selection of elements
  • +
  • move/drag of elements
  • +
  • save SVG file to separate tab
  • +
  • create and edit text elements
  • +
  • contextual panel of tools
  • +
  • change rect radius, font-family, font-size
  • +
  • keystroke handling
  • +
+

_

+
+
+ +
+
+
+

History: version 2.2 (8th July 2009)

+
+
    +
  • Multiselect Mode
  • +
  • Undo/Redo Actions
  • +
  • Resize Elements
  • +
  • Contextual tools for rect, circle, ellipse, line, text elements
  • +
  • Some updated button images
  • +
  • Stretched the UI to fit the browser window
  • +
  • Resizing of the SVG canvas
  • +
+

_

+
+
+ +
+
+
+

History: version 2.3 (8th Sept 2009)

+
+
    +
  • Align Objects
  • +
  • Rotate Objects
  • +
  • Clone Objects
  • +
  • Select Next/Prev Object
  • +
  • Edit SVG Source
  • +
  • Gradient picking
  • +
  • Polygon Mode (Path Editing, Phase 1)
  • +
+

_

+
+
+ +
+
+
+

History: version 2.4 (11th Jan 2010)

+
+
    +
  • Raster Images
  • +
  • Select Non-Adjacent Elements
  • +
  • Group/Ungroup
  • +
  • Zoom
  • +
  • Layers
  • +
  • Curve Segments in Paths
  • +
  • UI Localization
  • +
  • Wireframe Mode
  • +
  • Change Background
  • +
  • Convert Shapes to Path
  • +
+

_

+
+
+ +
+
+
+

History: version 2.5 (15th June 2010)

+
+
    +
  • Open Local Files (Fx 3.6+, Chrome 6+ only)
  • +
  • Import SVG into Drawing (Fx 3.6+, Chrome 6+ only)
  • +
  • Connector lines and Arrows
  • +
  • Smoother freehand paths
  • +
  • Editing outside the canvas
  • +
  • Increased support for SVG elements
  • +
  • Add/edit Sub-paths
  • +
  • Multiple path segment selection
  • +
  • Support for foreign markup (MathML)
  • +
  • Radial Gradients
  • +
  • Eye-dropper tool
  • +
  • Stroke linejoin and linecap
  • +
  • Export to PNG
  • +
+

_

+
+
+ +
+
+
+

Plugin Architecture

+
+
+svgEditor.addExtension("Hello World", function() {
+
+        return {
+                svgicons: "extensions/helloworld-icon.xml",
+                buttons: [{...}],
+                mouseDown: function() {
+                        ...
+                },
+
+                mouseUp: function(opts) {
+                        ...
+                }
+        };
+});
+
+
+ +
+
+
+

Features being implemented right now

+
+
    +
  • IE9 support
  • +
  • Linking off to clipart/image library sites
  • +
  • Context menus
  • +
+
+
+ +
+
+

Demo

+

stable

+

trunk

+
+
+ +
+
+
+

Projects based on SVG-edit

+
+
    +
  • Firefox add-on
  • +
  • Opera widget
  • +
  • Google Wave gadget
  • +
  • Wiki extensions (Dokuwiki, Instiki, MoinMoin, XWiki)
  • +
  • Cloud Canvas
  • +
  • Eduvid
  • +
  • Sesame
  • +
+
+
+ +
+
+
+

Resources

+
+ +
+
+ +
+
+

Thank you!

+

Questions?

+
+
+ +
+ +
+ + + + + + + diff --git a/screencasts/svgopen2010/logo.svg b/screencasts/svgopen2010/logo.svg new file mode 100644 index 00000000..e71308be --- /dev/null +++ b/screencasts/svgopen2010/logo.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + Layer 1 + + + + + + + + + + + + Layer 2 + + + diff --git a/screencasts/svgopen2010/script.js b/screencasts/svgopen2010/script.js new file mode 100644 index 00000000..28f9f90f --- /dev/null +++ b/screencasts/svgopen2010/script.js @@ -0,0 +1,390 @@ + (function() { + var doc = document; + var disableBuilds = true; + + var ctr = 0; + var spaces = /\s+/, a1 = ['']; + + var toArray = function(list) { + return Array.prototype.slice.call(list || [], 0); + }; + + var byId = function(id) { + if (typeof id == 'string') { return doc.getElementById(id); } + return id; + }; + + var query = function(query, root) { + if (!query) { return []; } + if (typeof query != 'string') { return toArray(query); } + if (typeof root == 'string') { + root = byId(root); + if(!root){ return []; } + } + + root = root || document; + var rootIsDoc = (root.nodeType == 9); + var doc = rootIsDoc ? root : (root.ownerDocument || document); + + // rewrite the query to be ID rooted + if (!rootIsDoc || ('>~+'.indexOf(query.charAt(0)) >= 0)) { + root.id = root.id || ('qUnique' + (ctr++)); + query = '#' + root.id + ' ' + query; + } + // don't choke on something like ".yada.yada >" + if ('>~+'.indexOf(query.slice(-1)) >= 0) { query += ' *'; } + + return toArray(doc.querySelectorAll(query)); + }; + + var strToArray = function(s) { + if (typeof s == 'string' || s instanceof String) { + if (s.indexOf(' ') < 0) { + a1[0] = s; + return a1; + } else { + return s.split(spaces); + } + } + return s; + }; + + var addClass = function(node, classStr) { + classStr = strToArray(classStr); + var cls = ' ' + node.className + ' '; + for (var i = 0, len = classStr.length, c; i < len; ++i) { + c = classStr[i]; + if (c && cls.indexOf(' ' + c + ' ') < 0) { + cls += c + ' '; + } + } + node.className = cls.trim(); + }; + + var removeClass = function(node, classStr) { + var cls; + if (classStr !== undefined) { + classStr = strToArray(classStr); + cls = ' ' + node.className + ' '; + for (var i = 0, len = classStr.length; i < len; ++i) { + cls = cls.replace(' ' + classStr[i] + ' ', ' '); + } + cls = cls.trim(); + } else { + cls = ''; + } + if (node.className != cls) { + node.className = cls; + } + }; + + var toggleClass = function(node, classStr) { + var cls = ' ' + node.className + ' '; + if (cls.indexOf(' ' + classStr.trim() + ' ') >= 0) { + removeClass(node, classStr); + } else { + addClass(node, classStr); + } + }; + + var ua = navigator.userAgent; + var isFF = parseFloat(ua.split('Firefox/')[1]) || undefined; + var isWK = parseFloat(ua.split('WebKit/')[1]) || undefined; + var isOpera = parseFloat(ua.split('Opera/')[1]) || undefined; + + var canTransition = (function() { + var ver = parseFloat(ua.split('Version/')[1]) || undefined; + // test to determine if this browser can handle CSS transitions. + var cachedCanTransition = + (isWK || (isFF && isFF > 3.6 ) || (isOpera && ver >= 10.5)); + return function() { return cachedCanTransition; } + })(); + + // + // Slide class + // + var Slide = function(node, idx) { + this._node = node; + if (idx >= 0) { + this._count = idx + 1; + } + if (this._node) { + addClass(this._node, 'slide distant-slide'); + } + this._makeCounter(); + this._makeBuildList(); + }; + + Slide.prototype = { + _node: null, + _count: 0, + _buildList: [], + _visited: false, + _currentState: '', + _states: [ 'distant-slide', 'far-past', + 'past', 'current', 'future', + 'far-future', 'distant-slide' ], + setState: function(state) { + if (typeof state != 'string') { + state = this._states[state]; + } + if (state == 'current' && !this._visited) { + this._visited = true; + this._makeBuildList(); + } + removeClass(this._node, this._states); + addClass(this._node, state); + this._currentState = state; + + // delay first auto run. Really wish this were in CSS. + /* + this._runAutos(); + */ + var _t = this; + setTimeout(function(){ _t._runAutos(); } , 400); + }, + _makeCounter: function() { + if(!this._count || !this._node) { return; } + var c = doc.createElement('span'); + c.innerHTML = this._count; + c.className = 'counter'; + this._node.appendChild(c); + }, + _makeBuildList: function() { + this._buildList = []; + if (disableBuilds) { return; } + if (this._node) { + this._buildList = query('[data-build] > *', this._node); + } + this._buildList.forEach(function(el) { + addClass(el, 'to-build'); + }); + }, + _runAutos: function() { + if (this._currentState != 'current') { + return; + } + // find the next auto, slice it out of the list, and run it + var idx = -1; + this._buildList.some(function(n, i) { + if (n.hasAttribute('data-auto')) { + idx = i; + return true; + } + return false; + }); + if (idx >= 0) { + var elem = this._buildList.splice(idx, 1)[0]; + var transitionEnd = isWK ? 'webkitTransitionEnd' : (isFF ? 'mozTransitionEnd' : 'oTransitionEnd'); + var _t = this; + if (canTransition()) { + var l = function(evt) { + elem.parentNode.removeEventListener(transitionEnd, l, false); + _t._runAutos(); + }; + elem.parentNode.addEventListener(transitionEnd, l, false); + removeClass(elem, 'to-build'); + } else { + setTimeout(function() { + removeClass(elem, 'to-build'); + _t._runAutos(); + }, 400); + } + } + }, + buildNext: function() { + if (!this._buildList.length) { + return false; + } + removeClass(this._buildList.shift(), 'to-build'); + return true; + }, + }; + + // + // SlideShow class + // + var SlideShow = function(slides) { + this._slides = (slides || []).map(function(el, idx) { + return new Slide(el, idx); + }); + + var h = window.location.hash; + try { + this.current = parseInt(h.split('#slide')[1], 10); + }catch (e) { /* squeltch */ } + this.current = isNaN(this.current) ? 1 : this.current; + var _t = this; + doc.addEventListener('keydown', + function(e) { _t.handleKeys(e); }, false); + doc.addEventListener('mousewheel', + function(e) { _t.handleWheel(e); }, false); + doc.addEventListener('DOMMouseScroll', + function(e) { _t.handleWheel(e); }, false); + doc.addEventListener('touchstart', + function(e) { _t.handleTouchStart(e); }, false); + doc.addEventListener('touchend', + function(e) { _t.handleTouchEnd(e); }, false); + window.addEventListener('popstate', + function(e) { _t.go(e.state); }, false); + this._update(); + }; + + SlideShow.prototype = { + _slides: [], + _update: function(dontPush) { + document.querySelector('#presentation-counter').innerText = this.current; + if (history.pushState) { + if (!dontPush) { + history.pushState(this.current, 'Slide ' + this.current, '#slide' + this.current); + } + } else { + window.location.hash = 'slide' + this.current; + } + for (var x = this.current-1; x < this.current + 7; x++) { + if (this._slides[x-4]) { + this._slides[x-4].setState(Math.max(0, x-this.current)); + } + } + }, + + current: 0, + next: function() { + if (!this._slides[this.current-1].buildNext()) { + this.current = Math.min(this.current + 1, this._slides.length); + this._update(); + } + }, + prev: function() { + this.current = Math.max(this.current-1, 1); + this._update(); + }, + go: function(num) { + if (history.pushState && this.current != num) { + history.replaceState(this.current, 'Slide ' + this.current, '#slide' + this.current); + } + this.current = num; + this._update(true); + }, + + _notesOn: false, + showNotes: function() { + var isOn = this._notesOn = !this._notesOn; + query('.notes').forEach(function(el) { + el.style.display = (notesOn) ? 'block' : 'none'; + }); + }, + switch3D: function() { + toggleClass(document.body, 'three-d'); + }, + handleWheel: function(e) { + var delta = 0; + if (e.wheelDelta) { + delta = e.wheelDelta/120; + if (isOpera) { + delta = -delta; + } + } else if (e.detail) { + delta = -e.detail/3; + } + + if (delta > 0 ) { + this.prev(); + return; + } + if (delta < 0 ) { + this.next(); + return; + } + }, + handleKeys: function(e) { + + if (/^(input|textarea)$/i.test(e.target.nodeName)) return; + + switch (e.keyCode) { + case 37: // left arrow + this.prev(); break; + case 39: // right arrow + case 32: // space + this.next(); break; + case 50: // 2 + this.showNotes(); break; + case 51: // 3 + this.switch3D(); break; + } + }, + _touchStartX: 0, + handleTouchStart: function(e) { + this._touchStartX = e.touches[0].pageX; + }, + handleTouchEnd: function(e) { + var delta = this._touchStartX - e.changedTouches[0].pageX; + var SWIPE_SIZE = 150; + if (delta > SWIPE_SIZE) { + this.next(); + } else if (delta< -SWIPE_SIZE) { + this.prev(); + } + }, + }; + + // Initialize + var slideshow = new SlideShow(query('.slide')); + + + + + + document.querySelector('#toggle-counter').addEventListener('click', toggleCounter, false); + document.querySelector('#toggle-size').addEventListener('click', toggleSize, false); + document.querySelector('#toggle-transitions').addEventListener('click', toggleTransitions, false); + document.querySelector('#toggle-gradients').addEventListener('click', toggleGradients, false); + + + var counters = document.querySelectorAll('.counter'); + var slides = document.querySelectorAll('.slide'); + + function toggleCounter() { + toArray(counters).forEach(function(el) { + el.style.display = (el.offsetHeight) ? 'none' : 'block'; + }); + } + + function toggleSize() { + toArray(slides).forEach(function(el) { + if (!/reduced/.test(el.className)) { + addClass(el, 'reduced'); + } + else { + removeClass(el, 'reduced'); + } + }); + } + + function toggleTransitions() { + toArray(slides).forEach(function(el) { + if (!/no-transitions/.test(el.className)) { + addClass(el, 'no-transitions'); + } + else { + removeClass(el, 'no-transitions'); + } + }); + } + + function toggleGradients() { + toArray(slides).forEach(function(el) { + if (!/no-gradients/.test(el.className)) { + addClass(el, 'no-gradients'); + } + else { + removeClass(el, 'no-gradients'); + } + }); + } + + + + + + })(); diff --git a/screencasts/svgopen2010/style.css b/screencasts/svgopen2010/style.css new file mode 100644 index 00000000..04b571c3 --- /dev/null +++ b/screencasts/svgopen2010/style.css @@ -0,0 +1,395 @@ + body { + font: 20px "Lucida Grande", "Trebuchet MS", Verdana, sans-serif; + padding: 0; + margin: 0; + width: 100%; + height: 100%; + position: absolute; + left: 0px; top: 0px; + } + + .presentation { + position: absolute; + height: 100%; + width: 100%; + left: 0px; + top: 0px; + display: block; + overflow: hidden; + background: #778; + } + + .slides { + width: 100%; + height: 100%; + left: 0; + top: 0; + position: absolute; + display: block; + -webkit-transition: -webkit-transform 1s ease-in-out; + -moz-transition: -moz-transform 1s ease-in-out; + -o-transition: -o-transform 1s ease-in-out; + transition: transform 1s ease-in-out; + + /* so it's visible in the iframe. */ + -webkit-transform: scale(0.8); + -moz-transform: scale(0.8); + -o-transform: scale(0.8); + transform: scale(0.8); + + } + + .slide { + display: none; + position: absolute; + overflow: hidden; + width: 900px; + height: 700px; + left: 50%; + top: 50%; + margin-top: -350px; + background-color: #eee; + background: -webkit-gradient(linear, left bottom, left top, from(#bbd), to(#fff)); + background: -moz-linear-gradient(bottom, #bbd, #fff); + background: linear-gradient(bottom, #bbd, #fff); + -webkit-transition: all 0.25s ease-in-out; + -moz-transition: all 0.25s ease-in-out; + -o-transition: all 0.25s ease-in-out; + transition: all 0.25s ease-in-out; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); + } + + .slide:nth-child(even) { + -moz-border-radius: 20px 0; + -khtml-border-radius: 20px 0; + border-radius: 20px 0; /* includes Opera 10.5+ */ + -webkit-border-top-left-radius: 20px; + -webkit-border-bottom-right-radius: 20px; + } + + .slide:nth-child(odd) { + -moz-border-radius: 0 20px; + -khtml-border-radius: 0 20px; + border-radius: 0 20px; + -webkit-border-top-right-radius: 20px; + -webkit-border-bottom-left-radius: 20px; + } + + .slide p, .slide textarea { + font-size: 120%; + } + + .slide .counter { + color: #999999; + position: absolute; + left: 20px; + bottom: 20px; + display: block; + font-size: 70%; + } + + .slide.title > .counter, + .slide.segue > .counter, + .slide.mainTitle > .counter { + display: none; + } + + .force-render { + display: block; + visibility: hidden; + } + + .slide.far-past { + display: block; + margin-left: -2400px; + } + + .slide.past { + visibility: visible; + display: block; + margin-left: -1400px; + } + + .slide.current { + visibility: visible; + display: block; + margin-left: -450px; + } + + .slide.future { + visibility: visible; + display: block; + margin-left: 500px; + } + + .slide.far-future { + display: block; + margin-left: 1500px; + } + + body.three-d div.slides { + -webkit-transform: translateX(50px) scale(0.8) rotateY(10deg); + -moz-transform: translateX(50px) scale(0.8) rotateY(10deg); + -o-transform: translateX(50px) scale(0.8) rotateY(10deg); + transform: translateX(50px) scale(0.8) rotateY(10deg); + } + + /* Content */ + + @font-face { font-family: 'Junction'; src: url(src/Junction02.otf); } + @font-face { font-family: 'LeagueGothic'; src: url(src/LeagueGothic.otf); } + + header { + font-family: 'Droid Sans'; + font-weight: normal; + letter-spacing: -.05em; + text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px; + left: 30px; + top: 25px; + margin: 0; + padding: 0; + font-size: 140%; + } + + h1 { + font-size: 140%; + display: inline; + font-weight: normal; + padding: 0; + margin: 0; + } + + h2 { + font-family: 'Droid Sans'; + color: black; + font-size: 120%; + padding: 0; + margin: 20px 0; + } + + h2:first-child { + margin-top: 0; + } + + section, footer { + font-family: 'Droid Sans'; + color: #3f3f3f; + text-shadow: rgba(0, 0, 0, 0.2) 0 2px 5px; + margin: 100px 30px 0; + display: block; + overflow: hidden; + } + + footer { + font-size: 100%; + margin: 20px 0 0 30px; + } + + a { + color: inherit; + display: inline-block; + text-decoration: none; + line-height: 110%; + border-bottom: 2px solid #3f3f3f; + } + + ul { + margin: 0; + padding: 0; + } + + li { + margin: 2%; + } + + button { + font-size: 100%; + } + + pre button { + margin: 2px; + } + + section.left { + float: left; + width: 390px; + } + + section.small { + font-size: 24px; + } + + section.small ul { + margin: 0 0 0 15px; + padding: 0; + } + + section.small li { + padding-bottom: 0; + } + + section.middle { + line-height: 2em; + text-align: center; + display: table-cell; + vertical-align: middle; + height: 700px; + width: 900px; + } + + pre { + text-align: left; + font-family: 'Droid Sans Mono', Courier; + font-size: 80%; + padding: 10px 20px; + background: rgba(255, 0, 0, 0.05); + -webkit-border-radius: 8px; + -khtml-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; + border: 1px solid rgba(255, 0, 0, 0.2); + } + + pre select { + font-family: Monaco, Courier; + border: 1px solid #c61800; + } + + input { + font-size: 100%; + margin-right: 10px; + font-family: Helvetica; + padding: 3px; + } + input[type="range"] { + width: 100%; + } + + button { + margin: 20px 10px 0 0; + font-family: Verdana; + } + + button.large { + font-size: 32px; + } + + pre b { + font-weight: normal; + color: #c61800; + text-shadow: #c61800 0 0 1px; + /*letter-spacing: -1px;*/ + } + pre em { + font-weight: normal; + font-style: normal; + color: #18a600; + text-shadow: #18a600 0 0 1px; + } + pre input[type="range"] { + height: 6px; + cursor: pointer; + width: auto; + } + + div.example { + display: block; + padding: 10px 20px; + color: black; + background: rgba(255, 255, 255, 0.4); + -webkit-border-radius: 8px; + -khtml-border-radius: 8px; + -moz-border-radius: 8px; + border-radius: 8px; + margin-bottom: 10px; + border: 1px solid rgba(0, 0, 0, 0.2); + } + + video { + -moz-border-radius: 8px; + -khtml-border-radius: 8px; + -webkit-border-radius: 8px; + border-radius: 8px; + border: 1px solid rgba(0, 0, 0, 0.2); + } + + .key { + font-family: 'Droid Sans'; + color: black; + display: inline-block; + padding: 6px 10px 3px 10px; + font-size: 100%; + line-height: 30px; + text-shadow: none; + letter-spacing: 0; + bottom: 10px; + position: relative; + -moz-border-radius: 10px; + -khtml-border-radius: 10px; + -webkit-border-radius: 10px; + border-radius: 10px; + background: white; + box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px; + -webkit-box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px; + -moz-box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px; + -o-box-shadow: rgba(0, 0, 0, 0.1) 0 2px 5px; + } + + .key { font-family: Arial; } + + :not(header) > .key { + margin: 0 5px; + bottom: 4px; + } + + .two-column { + -webkit-column-count: 2; + -moz-column-count: 2; + column-count: 2; + } + + .stroke { + -webkit-text-stroke-color: red; + -webkit-text-stroke-width: 1px; + } /* currently webkit-only */ + + .center { + text-align: center; + } + + #presentation-counter { + color: #ccc; + font-size: 70%; + letter-spacing: 1px; + position: absolute; + top: 40%; + left: 0; + width: 100%; + text-align: center; + } + + div:not(.current).reduced { + -webkit-transform: scale(0.8); + -moz-transform: scale(0.8); + -o-transform: scale(0.8); + transform: scale(0.8); + } + + .no-transitions { + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; + } + + .no-gradients { + background: none; + background-color: #fff; + } + + ul.bulleted { + padding-left: 30px; + }