在查询文章详情的界面,既要显示文章的正文文本信息,又要显示文章对应的图片,还要把图片上对应的关键字标红,如图为查询文章中“李”字:
SVG图片格式分析
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0px" y="0px" width="1030.0" height="1832.0"
viewBox="0 0 1030.0 1832.0"
xml:space="preserve">
<image id="image0" x="0.0" y="0.0" width="1030.0" height="1832.0" href="" />
<polygon points="812.76,418.01 968.16,418.57 968.76,543.12 812.96,542.62" style="fill:red;fill-opacity:0.5"/>
</svg>
值得我们注意的有以下几点:
- svg标签下的width height 这表示图宽高,如果width和height发生变化,svg整体就会发生变化,即图片和绘制的多边形都会变化
- viewBox是显示svg的容器,如果尺寸比svg小,会导致图片显示不全,过大会导致错位,可借此实现居中效果
- image 标签下的宽高影响图片,而不影响多边形
- polygon绘制多边形把搜索关键词在图片上标红,每个字都对应一个polygon标签
因此,要想构造出svg,需要如下参数:图片的width、height、href以及关键词的坐标
构造SVG
需要接收前端传来的两个参数:
aid:文章id,需要此id才能在solr里找到对应的图片链接
keyword:搜索关键词,配合aid在character核心中找到该文章中对应的字,从而获取字的页号和坐标
查询character的方法如下:
public JSONArray queryCharacter(String corename,String field, String keyword, String article) throws SolrServerException, IOException {
System.out.println(field+":"+keyword);
SolrQuery solrQuery=new SolrQuery();
StringBuilder query = new StringBuilder();
query.append("articles:").append(article).append(" && (");
for(int i=0;i<keyword.length();i++){
query.append(field).append(":").append(keyword.charAt(i));
if(i<keyword.length()-1){
query.append(" || ");
}
}
query.append(")");
System.out.println(String.valueOf(query));
solrQuery.setQuery(String.valueOf(query));
QueryResponse queryResponse = solrClient.query(corename,solrQuery);
SolrDocumentList results = queryResponse.getResults();
JSONArray jsonArray = new JSONArray();
for (SolrDocument document:results) {
System.out.println(document);
jsonArray.add(document);
}
return jsonArray;
}
但是, 由于前端容器尺寸的不确定性,要想使svg符合前端的尺寸要求,需要进行缩放 ,因此还需要两个参数:
width:前端所能接受的最大宽度
height:前端所能接受的最大高度
现在可以开始写svg的生成方法了
//获取aid对应的文章
JSONArray article_array = this.queryArticle("dms_article","_id", aid);
SolrDocument article = (SolrDocument) article_array.get(0);
System.out.println("article=" + article);
SolrDocument是可以根据key来获取value,但是返回的类型为Object,而我们的page属性为list,虽然可以通过强制类型转换把Object转换为list,但是得到的list的成员为String,不能达到解析取值的目的,因此需要手写解析器
原始的page属性如下:
page=[{src=, width=1030.0, id=Page.2, height=1832.0}, {src=, width=1030.0, id=Page.1, height=1832.0}]
解析方法如下:
private ArrayList<HashMap<String, String>> getPageInfo(ArrayList list){
ArrayList<HashMap<String, String>> output = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
String str = (String)list.get(i);
HashMap<String, String> map = new HashMap<String, String>();
String key = "", value = "";
boolean status = false;
for(int j = 0; j < str.length(); j ++){
char c = str.charAt(j);
switch(c){
case '{':
break;
case '=':
if(status)
value += c;
else
status = true;
break;
case '}':
map.put(key, value);
break;
case ',':
if(str.charAt(j + 1) == ' ')
j += 1;
status = false;
map.put(key, value);
key = "";
value = "";
break;
default:
if(status)
value += c;
else
key += c;
}
}
output.add(map);
}
return output;
}
解析完成后,返回的list的每一个元素都是一个HashMap,可以直接进行取值
//得到文章对应的page列表
ArrayList<HashMap<String, String>> list = this.getPageInfo((ArrayList)article.get("page"));
ArrayList<PageInfo> page_list = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
PageInfo info = new PageInfo(list.get(i));
//进行缩放的操作
info.setScale(width, height);
page_list.add(info);
}
PageInfo是自定义的类,保存了这一页的src、width、height、缩放、标记多边形等信息,以及最后生成svg图片的操作
public class PageInfo{
private String src = "";
private String id = "";
private double width = 0;
private double height = 0;
private double scale_width = 0;
private double scale_height = 0;
private double max_width = 0;
private double max_height = 0;
private double scale = 1;
private double x = 0;
private double y = 0;
private String polygons = "";
public PageInfo(HashMap<String, String> map){
this.src = map.get("src");
this.id = map.get("id");
this.width = Double.parseDouble(map.get("width"));
this.height = Double.parseDouble(map.get("height"));
this.polygons = "";
this.max_width = 0;
this.max_height = 0;
this.scale_width = 0;
this.scale_height = 0;
this.scale = 1;
this.x = 0;
this.y = 0;
}
public void setScale(String max_w, String max_h){
this.max_width = Double.parseDouble(max_w);
this.max_height = Double.parseDouble(max_h);
double scale_x = this.max_width / this.width;
double scale_y = this.max_height / this.height;
this.scale = Math.min(scale_x, scale_y);
this.scale_width = this.width * this.scale;
this.scale_height = this.height * this.scale;
this.x = (max_width - scale_width) / 2;
this.y = (max_height - scale_height) / 2;
}
public void addPolygon(ArrayList<String> list){
this.polygons += "<polygon points=\"";
for (int i = 0; i < list.size(); i+=2) {
double x = this.x + Double.parseDouble(list.get(i)) * this.scale;
double y = this.y + Double.parseDouble(list.get(i + 1)) * this.scale;
this.polygons += x + "," + y + " ";
}
this.polygons = this.polygons.substring(0, this.polygons.length() - 1);
this.polygons += "\" style=\"fill:red;fill-opacity:0.5\"/>\n";
}
public String toString(){
return "<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" " +
"xmlns:xlink=\"http://www.w3.org/1999/xlink\" " +
"x=\"0px\" y=\"0px\" width=\"" + this.max_width + "\" height=\"" + this.max_height + "\" " +
"viewBox=\"0 0 " + this.max_width + " " + this.max_height + "\" " +
"xml:space=\"preserve\"> \n" +
"<image id=\"image0\" x=\"" + this.x + "\" y=\"" + this.y + "\" width=\"" + this.scale_width +
"\" height=\"" + this.scale_height + "\" href=\""+ this.src+"\" />\n" +
this.polygons +
"</svg>";
}
public double getWidth() {
return width;
}
public double getHeight() {
return height;
}
public String getId() {
return id;
}
}
实现缩放的原理是讲前端传来所能容纳的最大宽高与文件实际宽高相除,最小者即为缩放比例
double scale_x = this.max_width / this.width;
double scale_y = this.max_height / this.height;
this.scale = Math.min(scale_x, scale_y);
之后便可计算得到缩放后的宽高,同时调整图片左上角的起始位置,使其居中
this.scale_width = this.width * this.scale;
this.scale_height = this.height * this.scale;
this.x = (max_width - scale_width) / 2;
this.y = (max_height - scale_height) / 2;
最后,把每个字的位置信息添加到svg中
//每一个字的信息
JSONArray char_array = this.queryCharacter("dms_character","character", keyword, aid);
List<SolrDocument> char_list = new ArrayList<>();
for(Object o : char_array){
char_list.add((SolrDocument) o);
}
for(SolrDocument s : char_list){
String page = (String)((ArrayList)s.get("page")).get(0);
ArrayList<String> position = (ArrayList)s.get("position");
for(PageInfo page_info : page_list){
if(page_info.getId().equals(page)){
page_info.addPolygon(position);
}
}
}
整体代码如下:
public String getSVG(String aid, String keyword, String width, String height) throws SolrServerException, IOException {
//获取aid对应的文章
JSONArray article_array = this.queryArticle("dms_article","_id", aid);
SolrDocument article = (SolrDocument) article_array.get(0);
//得到文章对应的page列表
ArrayList<HashMap<String, String>> list = this.getPageInfo((ArrayList)article.get("page"));
ArrayList<PageInfo> page_list = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
PageInfo info = new PageInfo(list.get(i));
//进行缩放的操作
info.setScale(width, height);
page_list.add(info);
}
//每一个字的信息
JSONArray char_array = this.queryCharacter("dms_character","character", keyword, aid);
List<SolrDocument> char_list = new ArrayList<>();
for(Object o : char_array){
char_list.add((SolrDocument) o);
}
for(SolrDocument s : char_list){
String page = (String)((ArrayList)s.get("page")).get(0);
ArrayList<String> position = (ArrayList)s.get("position");
for(PageInfo page_info : page_list){
if(page_info.getId().equals(page)){
page_info.addPolygon(position);
}
}
}
return page_list.toString();
}
这样就给前端返回了svg图片信息
轻舟已过万重山