Last modified on 9 July 2009, at 20:44

XForms/Supply and Demand

MotivationEdit

You want to create a simple illustration of a concept using a dynamic graph. You want to use a range control to change in input and see the impact of that change on an output.

Screen ImageEdit

Supply and Demand Dynamic Graph

Sample ProgramEdit

This is not working yet with the range control. I wrote it with just SVG and JavaScript and I am in the process of porting it to XForms. I also need to use CSS to clean up the markup.


<?xml version="1.0" encoding="utf-8"?>
<html 
xmlns="http://www.w3.org/1999/xhtml"
xmlns:xf="http://www.w3.org/2002/xforms"
xmlns:ev="http://www.w3.org/2001/xml-events"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">

<svg 
xmlns="http://www.w3.org/2000/svg"
xml:space="preserve" width="300" height="450" onload="OnLoadEvent(evt)">
        <defs>
                <g id="arrowMarker">
                        <g stroke="black" stroke-width="1">
                                <line x1="6" y1="-2" x2="0" y2="0"/>
                                <line x1="6" y1="+2" x2="0" y2="0"/>
                        </g>
                </g>
                <marker id="startMarker" markerWidth="48" markerHeight="24" viewBox="-4 -4 25 5" orient="auto" refX="0" refY="0" markerUnits="strokeWidth">
                        <g>
                                <use xlink:href="#arrowMarker" transform="rotate(180)" stroke-width="1" stroke="black"/>
                        </g>
                </marker>
        </defs>
        <!-- Title -->
        <text x="125" y="30" style="text-anchor:middle; font-family:Ariel-Narrow; font-weight:bold; font-size:18">Price and Demand</text>
        <!-- bounding box including all elements -->
        <rect x="10" y="10" width="250" height="430" style="stroke:black; stroke-width:2; fill:none"/>
        
        <!-- all drawing is done with the origin being at (0,0) -->
        <!-- graph itself -->
        <g transform="translate(30 40)">
                <!-- vertical price axis  -->
                <line x1="0" x2="0" y1="200" y2="0" style="fill:none;stroke:black;stroke-width:1;" marker-end="url(#startMarker)"/>
                <text x="15" y="10">P</text>
                <!-- horizontal axis quantity-->
                <line x1="0" x2="200" y1="200" y2="200" style="fill:none;stroke:black;stroke-width:1;" marker-end="url(#startMarker)"/>
                <text x="205" y="205">Q</text>
                <!-- fixed demmand curve -->
                <path id="demmand_curve" style="stroke:red; stroke-width:3" d="M0,0 200,200"/>
                <text x="120" y="-10" transform="rotate(45)">Demand</text>
                <!-- initial value of price -->
                <circle id="newPrice" cx="0" cy="100" r="4" style="stroke:blue; fill:blue"/>
                
                <text id="priceLabel" x="163" y="20" style="text-anchor:end">Input: Price =</text>
                <text id="priceText" x="163" y="20">100</text>
                
                <text id="quantityLabel" x="163" y="35" style="text-anchor:end">Output: Quantity =</text>
                <text id="quantityText" x="163" y="35">100</text>
                
                <line id="vertLine" x1="100" y1="100" x2="100" y2="200" style="stroke-dasharray: 1, 4;stroke:black;stroke-width:1; "/>
                <line id="horizLine" x1="0" y1="100" x2="100" y2="100" style="stroke-dasharray: 1, 4;stroke:black;stroke-width:1; "/>
                
                <g id="explanation" transform="translate(0 260)">
                        <text x="10" y="0">Adjust price by moving the slider.</text>
                        <text x="0" y="50">Note that as the input (price) changes.</text>
                        <text x="10" y="65">the quantity sold also changes.</text>
                        <text x="0" y="90">At high prices a low quantity is sold.</text>
                        <text x="0" y="110">At low prices a high quantity is sold.</text>
                </g>
        
        <g id="slider" transform="translate(0 220)" xoffset="30">
                <rect x="0" y="0" width="210" height="20" style="fill:#c0c0c0"/>
                <line style="stroke:black;stroke-width:2;" x1="5" y1="6" x2="205" y2="6"/>
                <line style="stroke:white;stroke-width:2;" x1="5" y1="8" x2="205" y2="8"/>
                <path style="stroke:black;fill:none;" d="M5,16 5,20 M25,16 25,20 M45,16 45,20 M65,16 65,20 M85,16 85,20 M105,16 105,20 M125,16 125,20 M145,16 145,20 M165,16 165,20 M185,16 185,20 M205,16 205,20"/>
                <g id="thumb" transform="translate(100 0)">
                        <path style="stroke:none;fill:#c0c0c0;" d="M1,2 1,12 5,15 9,12 9,2 Z"/>
                        <path style="stroke:white;fill:none;" d="M9,1 1,1 1,11"/>
                        <path style="stroke:black;fill:none;" d="M5,16 10,12 10,2"/>
                </g>
                
                <g id="explanation" transform="translate(20 230)">
                        <text x="0" y="0">Note that as the input (price) moves, the quantity sold changes.</text>
                        <text x="0" y="20">At high prices a low quantity is sold.</text>
                        <text x="0" y="40">At low prices a high low quantity is sold.</text>
                </g>
        </g>
        
        </g>
        <script><![CDATA[
// == Slider object based on version by Dr. Stefan Goessner at http://www.mecxpert.de/svg/slider.html
var slider=null, thumb=null, sliderActive = false;
var newPrice=null, priceText=null,  quantityText=null, vertLine=null, horizLine=null;
// -----------------------------------------------------------
function SliderDown(event)
{
   sliderActive = true;
}
function SliderUp(event)
{
   sliderActive = false;
   // window.status = "slider is inactive";
}
function SliderMove(event)
{
   var value = event.getClientX() - parseFloat(slider.getAttribute("xoffset")) - 4;
   if (sliderActive && value > 0 && value < 200)
   {
      thumb.setAttribute("transform", "translate(" + (value) + " 0)");
      SliderCallback(value);
   }
}

function SliderClick(event)
{
   var value = event.getClientX() - parseFloat(slider.getAttribute("xoffset")) - 4;
   if (value > 0 && value < 200)
   {
      thumb.setAttribute("transform", "translate(" + (value) + " 0)");
      SliderCallback(value);
   }
}

function SliderCallback(val)
{
// this is where we change the values
newPrice.setAttribute("cy", val);
horizLine.setAttribute("y1", val);
horizLine.setAttribute("y2", val);
horizLine.setAttribute("x2", val);
vertLine.setAttribute("x1", val);
vertLine.setAttribute("x2", val);
vertLine.setAttribute("y1", val);
priceText.firstChild.nodeValue=(200-val);
quantityText.firstChild.nodeValue=(val);
//= Math.round((val*1000)/1000);
window.status = "price is " + (val);
}

function OnLoadEvent(event) // called, when svg file is loaded (s. onLoad=..) ..
{
   var doc = event.getTarget() != null ? event.getTarget().getOwnerDocument() : null;
   if (doc != null)
   {
      slider = doc.getElementById("slider");
      thumb = doc.getElementById("thumb");
      newPrice = doc.getElementById("newPrice");
      priceText = doc.getElementById("priceText");
      quantityText = doc.getElementById("quantityText");
      vertLine = doc.getElementById("vertLine");
      horizLine = doc.getElementById("horizLine");
      slider.addEventListener("mousedown", SliderDown, false);
      slider.addEventListener("mouseup", SliderUp, false);
      slider.addEventListener("mousemove", SliderMove, false);
      slider.addEventListener("click", SliderClick, false);
        }
}
]]></script>
</svg>
<header>
<xf:model>
<xf:instance xmlns="">
   <data>
      <price>100</price>
   </data>
</xf:instance>
</xf:model>
</header>
<body>
<xf:range ref="price" start="0" end="200" step="1">
   <xf:label>Price: </xf:label>
</xf:range>
<xf:output ref="price" >
   <xf:label>Price: </xf:label>
</xf:output>
</body>
</html>

DiscussionEdit

Next Page: Event Logger | Previous Page: Venn Diagram

Home: XForms