All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.citec.scie.web.exporter.html.HtmlExporter Maven / Gradle / Ivy

Go to download

Module providing the webservice interface based on the Jetty embedded webserver and the FreeMarker template engine. Defines a simple format for providing textual annotations and produced output in HTML or JSON. This module has no dependencies to the other SCIE modules (except for the PDF text extractor) or the UIMA framework and thus can be used in any context, where text is annotated by an algorithm and should be presented to an end user.

The newest version!
/*
 * SCIE -- Spinal Cord Injury Information Extraction
 * Copyright (C) 2013, 2014
 * Raphael Dickfelder, Jan Göpfert, Benjamin Paaßen, Andreas Stöckel
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 */

package de.citec.scie.web.exporter.html;

import de.citec.scie.web.analysis.AbstractAnalysisResult;
import de.citec.scie.web.exporter.AbstractExporter;
import de.citec.scie.web.exporter.generic.NestedWriter;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

/**
 *
 * @author Andreas Stöckel -- [email protected]
 */
public class HtmlExporter implements AbstractExporter {

	private static final int DEFAULT_HUE = 217;
	private static final int LUMA_START = 60;
	private static final int LUMA_END = 90;
	private static final int SATU_START = 80;
	private static final int SATU_END = 50;
	private static final int HUE_DRIFT = 2;

	private static class HSLColor {

		public int h, s, l;

		public HSLColor(int h, int s, int l) {
			this.h = h;
			this.s = s;
			this.l = l;
		}

		public String cssValue(double a) {
			return String.format(Locale.US, "hsla(%d,%d%%,%d%%,%g)", h, s, l, a);
		}

	}

	private static void addHuesEntry(Map> hues, int gid, int hue) {
		if (hues.containsKey(hue)) {
			hues.get(hue).add(gid);
		} else {
			Set gids = new TreeSet<>();
			gids.add(gid);
			hues.put(hue, gids);
		}
	}

	private static int generateHue(Integer[] hues) {
		final int len = hues.length;

		// Special case: hues is empty, return default value
		if (len == 0) {
			return DEFAULT_HUE;
		}
		// Special case: hues has only one element, return complementary color
		if (len == 1) {
			return (hues[0] + 180) % 360;
		}

		// Fetch the range of two hues with the largest difference, choose the
		// color in between
		Arrays.sort(hues);
		int maxDistance = 0;
		int maxHue = 0;
		for (int i = 0; i < len; i++) {
			final int distance;
			if (i + 1 < len) {
				distance = hues[i + 1] - hues[i];
			} else {
				distance = hues[0] + 360 - hues[i];
			}
			if (maxDistance < distance) {
				maxDistance = distance;
				maxHue = (hues[i] + distance / 2) % 360;
			}
		}
		return maxHue;
	}

	private static Map generateColors(Set groups,
			AbstractAnalysisResult result) {
		// Map containing the assigned hues and the corresponding groups
		Map> hues = new TreeMap<>();

		// Insert all groups which have a hue assigned
		for (int gid : groups) {
			final Integer hue = result.getGroupHue(gid);
			if (hue != null) {
				addHuesEntry(hues, gid, hue);
			}
		}

		// Assign a hue to all groups with no explicit hue set
		for (int gid : groups) {
			final Integer hue = result.getGroupHue(gid);
			if (hue == null) {
				Integer[] hueKeys = new Integer[hues.size()];
				hues.keySet().toArray(hueKeys);
				addHuesEntry(hues, gid, generateHue(hueKeys));
			}
		}

		// Generate the HSL-Colors for each group
		Map res = new TreeMap<>();
		for (Map.Entry> hue : hues.entrySet()) {
			final Set gids = hue.getValue();
			final int len = gids.size();
			int idx = 0;
			for (int gid : gids) {
				int h = hue.getKey() + HUE_DRIFT * idx;
				int s = SATU_START
						+ (SATU_END - SATU_START) / len * idx;
				int l = LUMA_START
						+ (LUMA_END - LUMA_START) / len * idx;
				res.put(gid, new HSLColor(h, s, l));
				idx++;
			}
		}
		return res;
	}

	public static String writeStyle(Set groups,
			AbstractAnalysisResult result) {
		final Map colors = generateColors(groups, result);
		final StringBuilder res = new StringBuilder();
		for (Integer gid : groups) {
			HSLColor c = colors.get(gid);
			res.append("\n.").append(HtmlFormater.groupName(gid)).append(" {\n");
			res.append("\tbackground-color: ").append(c.cssValue(0.4)).append(";\n");
			res.append("}\n");
			res.append("\n.").append(HtmlFormater.groupName(gid)).append(".active {\n");
			res.append("\tbackground-color: ").append(c.cssValue(0.6)).append(";\n");
			res.append("}\n");
			res.append("\n.").append(HtmlFormater.groupName(gid)).append(".opaque {\n");
			res.append("\tbackground-color: ").append(c.cssValue(1.0)).append(";\n");
			res.append("}\n");
		}
		return res.toString();
	}

	@Override
	public void export(StringBuilder sb, AbstractAnalysisResult result) {
		// Create the HTML format instance and plug it into the generic nested
		// writer
		HtmlFormater formater = new HtmlFormater(result);
		NestedWriter writer = new NestedWriter(result, formater);

		// Generate the HTML
		String html = writer.write();

		// Generate the style description
		String style = writeStyle(formater.getGroups(), result);

		sb.append("
\n"); sb.append("\t\n"); sb.append(html); sb.append("\n
\n"); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy