package e4s.tutorial; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.text.SimpleDateFormat; import java.util.Calendar; import javax.imageio.ImageIO; import javax.servlet.http.HttpServletResponse; import e4s.html.*; import e4s.html.ajax.E4AjaxData; import e4s.html.ajax.E4AjaxData_Intf; import e4s.html.input.extended.E4Fieldset; import e4s.html.input.extended.E4InputFieldName; import e4s.html.input.extended.SELECT; import e4s.html.input.extended.E4SelectValues; import e4s.html.style.E4StylesHash; import e4s.servlet.E4ModuleImplementation; import e4s.servlet.E4ServletImplementation_Intf; import e4s.servlet.E4ServletImplementation_Servlet; import e4s.translate.E4TranslationsVec; import e4s.util.E4StringBufferHtml; import e4s.util.E4ScriptsVec; /** * This is a full example of a small application. * * The user must enter 3 values (day, month, year) and using an Ajax element and a dynamic * generated image a biorythm is calculated and drawn. Please note, that most code of this * example is dedecated to calculate and draw the image which is not core part of the E4S * framework. * * * {@tutorial Example_App_Biorythm} * */ public class Example_App_Biorythm extends E4ModuleImplementation { public static E4Method start = new E4Method(50000,"Biorythmus Example",false); public static E4MethodSilent createimg = new E4MethodSilent(false); private final static E4InputFieldName PARAM_DAY = E4InputFieldName.ANY(); private final static E4InputFieldName PARAM_MONTH = E4InputFieldName.ANY(); private final static E4InputFieldName PARAM_YEAR = E4InputFieldName.ANY(); /** * This is our Ajax output, it is involved after a change on the form * but just places an image on the screen, that image is rendered in * a function "createimg". */ private static class AjaxOutput extends E4AjaxData implements E4AjaxData_Intf { /** * Get an identification for this Ajax data object, for the case that more * instances of this object are used within the same session, then a unique * identifier is required. */ public String getDivId() { return getClass().getName(); } public boolean runWithoutLogin() { return true; } public void toHtml( E4StringBufferHtml buf, E4CgiParams params, E4ServletImplementation_Intf servlet, boolean initial ) { try { // Construct an URL that contains of the E4Method associated with function "createimg" // and additionally place the parameters received to that URL String url = createimg.constructUrl(servlet) + params.toCgiCall(); // Create an image with that URL, use no documentbase as this is included complete in the url. IMG img = new IMG(url,E4DocumentBase.EMPTY); // Set width and height of the image img.setWidth(640); img.setHeight(200); // render the image img.toHtml(buf,servlet); } catch( Error e ) { TRACE(e); } catch( Exception e ) { TRACE(e); } } } public void start( HTML html ) { try { html.setTitle("element4solution - biorythm example"); BODY body = html.BODY(); // this is the data object, it will be displayed asynchronly whenever // the user clicks on the "Calculate" button AjaxOutput ajaxout = new AjaxOutput(); // this is the Ajax Element, compatible with the E4S framework and // cab be integrated into e.g. the FORM element. Basically, the ae element // is a DIV tag with a specified - or in this case - unique generic // identification. E4AjaxElement ajaxelem = new E4AjaxElement(ajaxout,640,200,getServlet()); // create a box, this will later contain the Input Form E4BoxRoundCorners boxInput = body.BoxRoundCorners(); boxInput.setCaption("Birthdate"); boxInput.setWidth(640); boxInput.setBorderColor(E4Color.ORANGE); // create an input form and add it to the E4BoxRoundCorners element in HTML FORM form = new FORM(); boxInput.addElement(form); // create a fieldset within that form (this is a layout issue only) E4Fieldset fieldset = form.FIELDSET(); Calendar today = Calendar.getInstance(); today.setTime(new java.util.Date()); // Create a select box for the day input, use a selection between 1 and 31 // set an event-handler "onchange" that calles the script provided by the Ajax element SELECT fDay = fieldset.SELECT(PARAM_DAY,"Day",E4SelectValues.createRangeSelection(1,31,1)); fDay.layoutToNextRow(false); fDay.setValue(today.get(Calendar.DAY_OF_MONTH)); fDay.setEventHandler(ajaxelem.getOnChange(form)); // Create a select box for the month input, use a selection between January and December // set an event-handler "onchange" that calles the script provided by the Ajax element SELECT fMonth = fieldset.SELECT(PARAM_MONTH,"Month",E4SelectValues.createMonthSelection()); fMonth.layoutToNextRow(false); fMonth.setValue(today.get(Calendar.MONTH)); fMonth.setEventHandler(ajaxelem.getOnChange(form)); // Create a select box for the year input, use a selection 1907 and 2007, // set an event-handler "onchange" that calles the script provided by the Ajax element SELECT fYear = fieldset.SELECT(PARAM_YEAR,"YEAR",E4SelectValues.createRangeSelection(1907,2007,1)); fYear.layoutToNextRow(false); fYear.setValue(today.get(Calendar.YEAR)); fYear.setEventHandler(ajaxelem.getOnChange(form)); body.P(); // create a box, this will later contain the Ajax-HTML element E4BoxRoundCorners boxOutput = body.BoxRoundCorners(); boxOutput.setCaption("Bio Rythmus"); boxOutput.setWidth(640); boxOutput.setBorderColor(E4Color.ORANGE); boxOutput.addElement(ajaxelem); // the body tag requires preperation (never forget this when using Ajax) ajaxelem.prepare(body); } catch( Error e ) { html.SystemError(e); } } /** * Create an image. The html output is left empty (do not write out anything here!) and we write direct * to the image using "image/jpg" as content type. This function has nothing to do with Ajax, if you know * the function's alias code and the parameter names (which in this example are non-transparent) you could * use the URL of this function in any IMG SRC=.. HTML tag. * * @param html not used here * @parm params the CGI parameters that hold the user's input values */ public void createimg( HTML html, E4CgiParams params ) throws Exception { try { // get the parameters and (if available) create a Calendar object with the date of birth int day = params.getInt(PARAM_DAY); int month = params.getInt(PARAM_MONTH); int year = params.getInt(PARAM_YEAR); Calendar born = null; if (day != -1) { born = Calendar.getInstance(); born.set(Calendar.YEAR,year); born.set(Calendar.MONTH,month); born.set(Calendar.DAY_OF_MONTH,day); } // create an image (this is awt stuff, it has nothing to do with servlet or E4S programming) BufferedImage bufferedImage = drawBiorythmImage(born); // get our servlet's context E4ServletImplementation_Servlet servlet = (E4ServletImplementation_Servlet)getServlet(); // write out the image servlet.writePng(bufferedImage); } catch( Exception e ) { TRACE(e); } } /** * Create an image using awt functionality. * * @return the created image */ private BufferedImage drawBiorythmImage(Calendar born) { final int WIDTH = 640; final int HEIGHT = 200; BufferedImage res = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB); Graphics g = res.getGraphics(); g.setColor(Color.white); g.fillRect(0,0,WIDTH,HEIGHT); try { if (born != null) { Calendar today = Calendar.getInstance(); today.setTime(new java.util.Date()); long diff = (today.getTimeInMillis() - born.getTimeInMillis()) / (24*60*60*1000); final int RANGE = 14; final int cycles[] = {23,28,33}; final String label[] = {"Body","Emotion","Sex"}; final Color color[] = {Color.GREEN,Color.BLUE,Color.RED}; g.setColor(Color.DARK_GRAY); g.drawLine(0,HEIGHT / 2,WIDTH,HEIGHT / 2); g.setFont(new Font("ARIAL",0,10)); g.setColor(Color.LIGHT_GRAY); g.drawLine(WIDTH - 1,0,WIDTH - 1,HEIGHT); FontMetrics fm = g.getFontMetrics(); SimpleDateFormat df = new SimpleDateFormat("dd.MMM"); for( int xday = -1 * RANGE; xday <= RANGE; xday++ ) { Calendar tmp = Calendar.getInstance(); tmp.setTime(new java.util.Date()); tmp.add(Calendar.DAY_OF_YEAR,xday); String sDat = df.format(tmp.getTime()); g.setColor(xday == 0 ? Color.DARK_GRAY : Color.LIGHT_GRAY); int xscreen = WIDTH / 2 + (int)((xday / (float)RANGE) * (WIDTH / 2.0f)); if (((xday % 2) == 0) && (xday != -RANGE) && (xday != RANGE)) { g.drawLine(xscreen,0,xscreen,188); g.setColor(Color.BLACK); g.drawString(sDat,xscreen - fm.stringWidth(sDat) / 2,HEIGHT - 1); } else { g.drawLine(xscreen,0,xscreen,HEIGHT); } } for( int k = 0; k < cycles.length; k++ ) { g.setColor(color[k]); int x0 = Integer.MAX_VALUE; int y0 = Integer.MAX_VALUE; for( int x = 0; x < WIDTH; x += 5 ) { float xday = diff + ((x - WIDTH / 2) / (WIDTH / 2.0f)) * RANGE; int y = 100 - (int)(90.0f * Math.sin((xday % cycles[k]) * 2.0 * Math.PI / cycles[k])); if (x0 == Integer.MAX_VALUE) { x0 = x; y0 = y; } g.drawLine(x0, y0, x, y); x0 = x; y0 = y; } } df = new SimpleDateFormat("dd.MMM yyyy"); String sBorn = df.format(born.getTime()) + " (" + diff + " days)"; drawLegend(g,10,10,sBorn,Color.BLACK); int x = 10; for( int k = 0; k < cycles.length; k++ ) { x += drawLegend(g,x,HEIGHT - 35,label[k],color[k]); } } g.dispose(); } catch( Error e ) { g.setColor(Color.RED); g.drawString(e.toString(),10,20); TRACE(e); } return res; } /** * This is part of the image generation. */ private int drawLegend(Graphics g, int x, int y, String s, Color color) { g.setFont(new Font("ARIAL",Font.BOLD,12)); FontMetrics fm = g.getFontMetrics(); int width = fm.stringWidth(s); int height = fm.getHeight(); g.setColor(Color.white); g.fillRect(x, y, 2 * 3 + width, 2 * 3 + height); g.setColor(color); g.drawRect(x, y, 2 * 3 + width, 2 * 3 + height); g.drawString(s,x + 3,y + height); return width + 12; } }