XForms/Supply and Demand

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Motivation[edit | edit source]

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 Image[edit | edit source]

Supply and Demand Dynamic Graph

Sample Program[edit | edit source]

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>

Discussion[edit | edit source]

Next Page: Event Logger | Previous Page: Venn Diagram
Home: XForms